From 2fb6dab580adf4d5d02a282b2ceccf9823370020 Mon Sep 17 00:00:00 2001 From: Lawrence Qiu Date: Tue, 19 Mar 2024 11:54:28 -0400 Subject: [PATCH 1/8] feat: Validate the Universe Domain inside Java-Core --- .../cloud/http/HttpTransportOptions.java | 20 ++ .../cloud/http/HttpTransportOptionsTest.java | 236 ++++++++++++++++++ 2 files changed, 256 insertions(+) diff --git a/java-core/google-cloud-core-http/src/main/java/com/google/cloud/http/HttpTransportOptions.java b/java-core/google-cloud-core-http/src/main/java/com/google/cloud/http/HttpTransportOptions.java index 4bdfee3cca..c386d13390 100644 --- a/java-core/google-cloud-core-http/src/main/java/com/google/cloud/http/HttpTransportOptions.java +++ b/java-core/google-cloud-core-http/src/main/java/com/google/cloud/http/HttpTransportOptions.java @@ -42,6 +42,7 @@ public class HttpTransportOptions implements TransportOptions { private static final long serialVersionUID = 7890117765045419810L; + private static final String GOOGLE_CLOUD_UNIVERSE_DOMAIN = "GOOGLE_CLOUD_UNIVERSE_DOMAIN"; private final int connectTimeout; private final int readTimeout; private final String httpTransportFactoryClassName; @@ -156,6 +157,25 @@ public HttpRequestInitializer getHttpRequestInitializer( @Override public void initialize(HttpRequest httpRequest) throws IOException { if (delegate != null) { + // delegate is always HttpCredentialsAdapter or null + HttpCredentialsAdapter httpCredentialsAdapter = (HttpCredentialsAdapter) delegate; + String credentialsUniverseDomain = + httpCredentialsAdapter.getCredentials().getUniverseDomain(); + String configuredUniverseDomain = serviceOptions.getUniverseDomain(); + if (configuredUniverseDomain == null) { + configuredUniverseDomain = System.getenv(GOOGLE_CLOUD_UNIVERSE_DOMAIN); + } + if (configuredUniverseDomain == null) { + configuredUniverseDomain = Credentials.GOOGLE_DEFAULT_UNIVERSE; + } + if (!configuredUniverseDomain.equals(credentialsUniverseDomain)) { + throw new IllegalStateException( + String.format( + "The configured universe domain (%s) does not match the universe domain found" + + " in the credentials (%s). If you haven't configured the universe domain" + + " explicitly, `googleapis.com` is the default.", + configuredUniverseDomain, credentialsUniverseDomain)); + } delegate.initialize(httpRequest); } if (connectTimeout >= 0) { diff --git a/java-core/google-cloud-core-http/src/test/java/com/google/cloud/http/HttpTransportOptionsTest.java b/java-core/google-cloud-core-http/src/test/java/com/google/cloud/http/HttpTransportOptionsTest.java index 1ff7871aec..b66fdc3e0b 100644 --- a/java-core/google-cloud-core-http/src/test/java/com/google/cloud/http/HttpTransportOptionsTest.java +++ b/java-core/google-cloud-core-http/src/test/java/com/google/cloud/http/HttpTransportOptionsTest.java @@ -19,12 +19,34 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; +import com.google.api.client.http.HttpRequest; +import com.google.api.client.http.HttpRequestInitializer; +import com.google.api.client.http.HttpTransport; +import com.google.api.client.http.LowLevelHttpRequest; +import com.google.api.client.http.LowLevelHttpResponse; +import com.google.api.client.testing.http.HttpTesting; +import com.google.api.client.testing.http.MockHttpTransport; +import com.google.api.client.testing.http.MockLowLevelHttpRequest; +import com.google.api.client.testing.http.MockLowLevelHttpResponse; import com.google.api.gax.rpc.HeaderProvider; +import com.google.auth.Credentials; import com.google.auth.http.HttpTransportFactory; +import com.google.cloud.BaseService; +import com.google.cloud.NoCredentials; +import com.google.cloud.Service; +import com.google.cloud.ServiceDefaults; +import com.google.cloud.ServiceFactory; import com.google.cloud.ServiceOptions; +import com.google.cloud.ServiceRpc; +import com.google.cloud.TransportOptions; import com.google.cloud.http.HttpTransportOptions.DefaultHttpTransportFactory; +import com.google.cloud.spi.ServiceRpcFactory; +import java.io.IOException; +import java.util.HashMap; +import java.util.Set; import java.util.regex.Pattern; import org.easymock.EasyMock; import org.junit.Test; @@ -43,6 +65,110 @@ public class HttpTransportOptionsTest { HttpTransportOptions.newBuilder().build(); private static final HttpTransportOptions OPTIONS_COPY = OPTIONS.toBuilder().build(); + interface TestService extends Service {} + + private static class TestServiceImpl extends BaseService + implements TestService { + private TestServiceImpl(TestServiceOptions options) { + super(options); + } + } + + public interface TestServiceFactory extends ServiceFactory {} + + private static class DefaultTestServiceFactory implements TestServiceFactory { + private static final TestServiceFactory INSTANCE = new DefaultTestServiceFactory(); + + @Override + public TestService create(TestServiceOptions options) { + return new TestServiceImpl(options); + } + } + + public interface TestServiceRpcFactory extends ServiceRpcFactory {} + + private static class DefaultTestServiceRpcFactory implements TestServiceRpcFactory { + private static final TestServiceRpcFactory INSTANCE = new DefaultTestServiceRpcFactory(); + + @Override + public TestServiceRpc create(TestServiceOptions options) { + return new DefaultTestServiceRpc(options); + } + } + + private interface TestServiceRpc extends ServiceRpc {} + + private static class DefaultTestServiceRpc implements TestServiceRpc { + DefaultTestServiceRpc(TestServiceOptions options) {} + } + + static class TestServiceOptions extends ServiceOptions { + private static class Builder + extends ServiceOptions.Builder { + private Builder() {} + + private Builder(TestServiceOptions options) { + super(options); + } + + @Override + protected TestServiceOptions build() { + return new TestServiceOptions(this); + } + } + + private TestServiceOptions(Builder builder) { + super( + TestServiceFactory.class, + TestServiceRpcFactory.class, + builder, + new TestServiceDefaults()); + } + + private static class TestServiceDefaults + implements ServiceDefaults { + + @Override + public TestServiceFactory getDefaultServiceFactory() { + return DefaultTestServiceFactory.INSTANCE; + } + + @Override + public TestServiceRpcFactory getDefaultRpcFactory() { + return DefaultTestServiceRpcFactory.INSTANCE; + } + + @Override + public TransportOptions getDefaultTransportOptions() { + return new TransportOptions() {}; + } + } + + @Override + protected Set getScopes() { + return null; + } + + @Override + public Builder toBuilder() { + return new Builder(this); + } + + private static Builder newBuilder() { + return new Builder(); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof TestServiceOptions && baseEquals((TestServiceOptions) obj); + } + + @Override + public int hashCode() { + return baseHashCode(); + } + } + @Test public void testBuilder() { assertEquals(1234, OPTIONS.getConnectTimeout()); @@ -78,4 +204,114 @@ public void testHeader() { .matcher(headerProvider.getHeaders().values().iterator().next()) .find()); } + + @Test + public void testHttpRequestInitializer_initializeHasValidUniverseDomain() throws IOException { + Credentials credentials = EasyMock.createMock(Credentials.class); + EasyMock.expect(credentials.getUniverseDomain()).andReturn(Credentials.GOOGLE_DEFAULT_UNIVERSE); + EasyMock.expect(credentials.hasRequestMetadata()).andReturn(false); + HeaderProvider headerProvider = EasyMock.createMock(HeaderProvider.class); + EasyMock.expect(headerProvider.getHeaders()).andReturn(new HashMap<>()); + EasyMock.replay(credentials, headerProvider); + + HttpTransport mockHttpTransport = + new MockHttpTransport() { + @Override + public LowLevelHttpRequest buildRequest(String method, String url) { + return new MockLowLevelHttpRequest() { + @Override + public LowLevelHttpResponse execute() { + return new MockLowLevelHttpResponse(); + } + }; + } + }; + HttpRequest httpRequest = + mockHttpTransport.createRequestFactory().buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL); + TestServiceOptions testServiceOptions = + TestServiceOptions.newBuilder() + .setCredentials(credentials) + .setHeaderProvider(headerProvider) + .setQuotaProjectId("testing") + .setProjectId("testing") + .build(); + HttpRequestInitializer httpRequestInitializer = + DEFAULT_OPTIONS.getHttpRequestInitializer(testServiceOptions); + httpRequestInitializer.initialize(httpRequest); + } + + @Test + public void + testHttpRequestInitializer_initializeHasInvalidUniverseDomain_throwsIllegalStateException() + throws IOException { + Credentials credentials = EasyMock.createMock(Credentials.class); + EasyMock.expect(credentials.getUniverseDomain()).andReturn("random.com"); + EasyMock.expect(credentials.hasRequestMetadata()).andReturn(false); + HeaderProvider headerProvider = EasyMock.createMock(HeaderProvider.class); + EasyMock.expect(headerProvider.getHeaders()).andReturn(new HashMap<>()); + EasyMock.replay(credentials, headerProvider); + + HttpTransport mockHttpTransport = + new MockHttpTransport() { + @Override + public LowLevelHttpRequest buildRequest(String method, String url) { + return new MockLowLevelHttpRequest() { + @Override + public LowLevelHttpResponse execute() { + return new MockLowLevelHttpResponse(); + } + }; + } + }; + HttpRequest httpRequest = + mockHttpTransport.createRequestFactory().buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL); + TestServiceOptions testServiceOptions = + TestServiceOptions.newBuilder() + .setCredentials(credentials) + .setHeaderProvider(headerProvider) + .setQuotaProjectId("testing") + .setProjectId("testing") + .build(); + HttpRequestInitializer httpRequestInitializer = + DEFAULT_OPTIONS.getHttpRequestInitializer(testServiceOptions); + IllegalStateException exception = + assertThrows( + IllegalStateException.class, () -> httpRequestInitializer.initialize(httpRequest)); + assertEquals( + "The configured universe domain (googleapis.com) does not match the universe domain found in the credentials (random.com). If you haven't configured the universe domain explicitly, `googleapis.com` is the default.", + exception.getMessage()); + } + + @Test + public void testHttpRequestInitializer_initializeNoCredentials_noThrow() throws IOException { + NoCredentials credentials = NoCredentials.getInstance(); + HeaderProvider headerProvider = EasyMock.createMock(HeaderProvider.class); + EasyMock.expect(headerProvider.getHeaders()).andReturn(new HashMap<>()); + EasyMock.replay(headerProvider); + + HttpTransport mockHttpTransport = + new MockHttpTransport() { + @Override + public LowLevelHttpRequest buildRequest(String method, String url) { + return new MockLowLevelHttpRequest() { + @Override + public LowLevelHttpResponse execute() { + return new MockLowLevelHttpResponse(); + } + }; + } + }; + HttpRequest httpRequest = + mockHttpTransport.createRequestFactory().buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL); + TestServiceOptions testServiceOptions = + TestServiceOptions.newBuilder() + .setCredentials(credentials) + .setHeaderProvider(headerProvider) + .setQuotaProjectId("testing") + .setProjectId("testing") + .build(); + HttpRequestInitializer httpRequestInitializer = + DEFAULT_OPTIONS.getHttpRequestInitializer(testServiceOptions); + httpRequestInitializer.initialize(httpRequest); + } } From 8b3813600f052ff2c2c906833f81ac0f7703c96f Mon Sep 17 00:00:00 2001 From: Lawrence Qiu Date: Tue, 19 Mar 2024 13:06:44 -0400 Subject: [PATCH 2/8] chore: Refactor resolving the universe domain --- .../google/cloud/http/HttpTransportOptions.java | 17 ++++++++++------- .../cloud/http/HttpTransportOptionsTest.java | 5 +++++ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/java-core/google-cloud-core-http/src/main/java/com/google/cloud/http/HttpTransportOptions.java b/java-core/google-cloud-core-http/src/main/java/com/google/cloud/http/HttpTransportOptions.java index c386d13390..46899c77f7 100644 --- a/java-core/google-cloud-core-http/src/main/java/com/google/cloud/http/HttpTransportOptions.java +++ b/java-core/google-cloud-core-http/src/main/java/com/google/cloud/http/HttpTransportOptions.java @@ -154,6 +154,15 @@ public HttpRequestInitializer getHttpRequestInitializer( serviceOptions.getMergedHeaderProvider(internalHeaderProvider); return new HttpRequestInitializer() { + + private String determineUniverseDomain() { + String universeDomain = serviceOptions.getUniverseDomain(); + if (universeDomain == null) { + universeDomain = System.getenv(GOOGLE_CLOUD_UNIVERSE_DOMAIN); + } + return universeDomain == null ? Credentials.GOOGLE_DEFAULT_UNIVERSE : universeDomain; + } + @Override public void initialize(HttpRequest httpRequest) throws IOException { if (delegate != null) { @@ -161,13 +170,7 @@ public void initialize(HttpRequest httpRequest) throws IOException { HttpCredentialsAdapter httpCredentialsAdapter = (HttpCredentialsAdapter) delegate; String credentialsUniverseDomain = httpCredentialsAdapter.getCredentials().getUniverseDomain(); - String configuredUniverseDomain = serviceOptions.getUniverseDomain(); - if (configuredUniverseDomain == null) { - configuredUniverseDomain = System.getenv(GOOGLE_CLOUD_UNIVERSE_DOMAIN); - } - if (configuredUniverseDomain == null) { - configuredUniverseDomain = Credentials.GOOGLE_DEFAULT_UNIVERSE; - } + String configuredUniverseDomain = determineUniverseDomain(); if (!configuredUniverseDomain.equals(credentialsUniverseDomain)) { throw new IllegalStateException( String.format( diff --git a/java-core/google-cloud-core-http/src/test/java/com/google/cloud/http/HttpTransportOptionsTest.java b/java-core/google-cloud-core-http/src/test/java/com/google/cloud/http/HttpTransportOptionsTest.java index b66fdc3e0b..c2ffffb16b 100644 --- a/java-core/google-cloud-core-http/src/test/java/com/google/cloud/http/HttpTransportOptionsTest.java +++ b/java-core/google-cloud-core-http/src/test/java/com/google/cloud/http/HttpTransportOptionsTest.java @@ -65,6 +65,11 @@ public class HttpTransportOptionsTest { HttpTransportOptions.newBuilder().build(); private static final HttpTransportOptions OPTIONS_COPY = OPTIONS.toBuilder().build(); + /** + * The following interfaces and classes are from ServiceOptionsTest. Copied over here as + * ServiceOptions resides inside google-cloud-core test folder and is not accessible from + * google-cloud-core-http. + */ interface TestService extends Service {} private static class TestServiceImpl extends BaseService From d9dcc1c737faeb0fb02e27eef7a7d830ea7bdade Mon Sep 17 00:00:00 2001 From: Lawrence Qiu Date: Wed, 3 Apr 2024 12:53:50 -0400 Subject: [PATCH 3/8] chore: Add more tests cases --- .../cloud/http/HttpTransportOptions.java | 36 +++-- .../cloud/http/HttpTransportOptionsTest.java | 141 ++++++++++++++++-- 2 files changed, 154 insertions(+), 23 deletions(-) diff --git a/java-core/google-cloud-core-http/src/main/java/com/google/cloud/http/HttpTransportOptions.java b/java-core/google-cloud-core-http/src/main/java/com/google/cloud/http/HttpTransportOptions.java index 46899c77f7..cc2102ccc8 100644 --- a/java-core/google-cloud-core-http/src/main/java/com/google/cloud/http/HttpTransportOptions.java +++ b/java-core/google-cloud-core-http/src/main/java/com/google/cloud/http/HttpTransportOptions.java @@ -155,6 +155,10 @@ public HttpRequestInitializer getHttpRequestInitializer( return new HttpRequestInitializer() { + /** + * Resolve the Universe Domain from ServiceOptions or the Environment Variable. Otherwise, + * resolve to the Google Default Universe. + */ private String determineUniverseDomain() { String universeDomain = serviceOptions.getUniverseDomain(); if (universeDomain == null) { @@ -165,22 +169,30 @@ private String determineUniverseDomain() { @Override public void initialize(HttpRequest httpRequest) throws IOException { + String configuredUniverseDomain = determineUniverseDomain(); + // Default to the GDU and override with value in the Credentials + String credentialsUniverseDomain = Credentials.GOOGLE_DEFAULT_UNIVERSE; + + // delegate is always HttpCredentialsAdapter or null (NoCredentials) if (delegate != null) { - // delegate is always HttpCredentialsAdapter or null HttpCredentialsAdapter httpCredentialsAdapter = (HttpCredentialsAdapter) delegate; - String credentialsUniverseDomain = - httpCredentialsAdapter.getCredentials().getUniverseDomain(); - String configuredUniverseDomain = determineUniverseDomain(); - if (!configuredUniverseDomain.equals(credentialsUniverseDomain)) { - throw new IllegalStateException( - String.format( - "The configured universe domain (%s) does not match the universe domain found" - + " in the credentials (%s). If you haven't configured the universe domain" - + " explicitly, `googleapis.com` is the default.", - configuredUniverseDomain, credentialsUniverseDomain)); - } + credentialsUniverseDomain = httpCredentialsAdapter.getCredentials().getUniverseDomain(); + } + + // Validate the universe domain before initializing the request + if (!configuredUniverseDomain.equals(credentialsUniverseDomain)) { + throw new IllegalStateException( + String.format( + "The configured universe domain (%s) does not match the universe domain found" + + " in the credentials (%s). If you haven't configured the universe domain" + + " explicitly, `googleapis.com` is the default.", + configuredUniverseDomain, credentialsUniverseDomain)); + } + + if (delegate != null) { delegate.initialize(httpRequest); } + if (connectTimeout >= 0) { httpRequest.setConnectTimeout(connectTimeout); } diff --git a/java-core/google-cloud-core-http/src/test/java/com/google/cloud/http/HttpTransportOptionsTest.java b/java-core/google-cloud-core-http/src/test/java/com/google/cloud/http/HttpTransportOptionsTest.java index c2ffffb16b..9307e72dde 100644 --- a/java-core/google-cloud-core-http/src/test/java/com/google/cloud/http/HttpTransportOptionsTest.java +++ b/java-core/google-cloud-core-http/src/test/java/com/google/cloud/http/HttpTransportOptionsTest.java @@ -64,6 +64,7 @@ public class HttpTransportOptionsTest { private static final HttpTransportOptions DEFAULT_OPTIONS = HttpTransportOptions.newBuilder().build(); private static final HttpTransportOptions OPTIONS_COPY = OPTIONS.toBuilder().build(); + private static final String DEFAULT_PROJECT_ID = "testing"; /** * The following interfaces and classes are from ServiceOptionsTest. Copied over here as @@ -211,7 +212,8 @@ public void testHeader() { } @Test - public void testHttpRequestInitializer_initializeHasValidUniverseDomain() throws IOException { + public void testHttpRequestInitializer_defaultUniverseDomain_defaultCredentials() + throws IOException { Credentials credentials = EasyMock.createMock(Credentials.class); EasyMock.expect(credentials.getUniverseDomain()).andReturn(Credentials.GOOGLE_DEFAULT_UNIVERSE); EasyMock.expect(credentials.hasRequestMetadata()).andReturn(false); @@ -237,8 +239,8 @@ public LowLevelHttpResponse execute() { TestServiceOptions.newBuilder() .setCredentials(credentials) .setHeaderProvider(headerProvider) - .setQuotaProjectId("testing") - .setProjectId("testing") + .setQuotaProjectId(DEFAULT_PROJECT_ID) + .setProjectId(DEFAULT_PROJECT_ID) .build(); HttpRequestInitializer httpRequestInitializer = DEFAULT_OPTIONS.getHttpRequestInitializer(testServiceOptions); @@ -246,9 +248,8 @@ public LowLevelHttpResponse execute() { } @Test - public void - testHttpRequestInitializer_initializeHasInvalidUniverseDomain_throwsIllegalStateException() - throws IOException { + public void testHttpRequestInitializer_defaultUniverseDomain_customCredentials() + throws IOException { Credentials credentials = EasyMock.createMock(Credentials.class); EasyMock.expect(credentials.getUniverseDomain()).andReturn("random.com"); EasyMock.expect(credentials.hasRequestMetadata()).andReturn(false); @@ -274,8 +275,8 @@ public LowLevelHttpResponse execute() { TestServiceOptions.newBuilder() .setCredentials(credentials) .setHeaderProvider(headerProvider) - .setQuotaProjectId("testing") - .setProjectId("testing") + .setQuotaProjectId(DEFAULT_PROJECT_ID) + .setProjectId(DEFAULT_PROJECT_ID) .build(); HttpRequestInitializer httpRequestInitializer = DEFAULT_OPTIONS.getHttpRequestInitializer(testServiceOptions); @@ -288,7 +289,86 @@ public LowLevelHttpResponse execute() { } @Test - public void testHttpRequestInitializer_initializeNoCredentials_noThrow() throws IOException { + public void testHttpRequestInitializer_customUniverseDomain_defaultCredentials() + throws IOException { + Credentials credentials = EasyMock.createMock(Credentials.class); + EasyMock.expect(credentials.getUniverseDomain()).andReturn(Credentials.GOOGLE_DEFAULT_UNIVERSE); + EasyMock.expect(credentials.hasRequestMetadata()).andReturn(false); + HeaderProvider headerProvider = EasyMock.createMock(HeaderProvider.class); + EasyMock.expect(headerProvider.getHeaders()).andReturn(new HashMap<>()); + EasyMock.replay(credentials, headerProvider); + + HttpTransport mockHttpTransport = + new MockHttpTransport() { + @Override + public LowLevelHttpRequest buildRequest(String method, String url) { + return new MockLowLevelHttpRequest() { + @Override + public LowLevelHttpResponse execute() { + return new MockLowLevelHttpResponse(); + } + }; + } + }; + HttpRequest httpRequest = + mockHttpTransport.createRequestFactory().buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL); + TestServiceOptions testServiceOptions = + TestServiceOptions.newBuilder() + .setCredentials(credentials) + .setHeaderProvider(headerProvider) + .setQuotaProjectId(DEFAULT_PROJECT_ID) + .setProjectId(DEFAULT_PROJECT_ID) + .setUniverseDomain("random.com") + .build(); + HttpRequestInitializer httpRequestInitializer = + DEFAULT_OPTIONS.getHttpRequestInitializer(testServiceOptions); + IllegalStateException exception = + assertThrows( + IllegalStateException.class, () -> httpRequestInitializer.initialize(httpRequest)); + assertEquals( + "The configured universe domain (random.com) does not match the universe domain found in the credentials (googleapis.com). If you haven't configured the universe domain explicitly, `googleapis.com` is the default.", + exception.getMessage()); + } + + @Test + public void testHttpRequestInitializer_customUniverseDomain_customCredentials() + throws IOException { + Credentials credentials = EasyMock.createMock(Credentials.class); + EasyMock.expect(credentials.getUniverseDomain()).andReturn("random.com"); + EasyMock.expect(credentials.hasRequestMetadata()).andReturn(false); + HeaderProvider headerProvider = EasyMock.createMock(HeaderProvider.class); + EasyMock.expect(headerProvider.getHeaders()).andReturn(new HashMap<>()); + EasyMock.replay(credentials, headerProvider); + + HttpTransport mockHttpTransport = + new MockHttpTransport() { + @Override + public LowLevelHttpRequest buildRequest(String method, String url) { + return new MockLowLevelHttpRequest() { + @Override + public LowLevelHttpResponse execute() { + return new MockLowLevelHttpResponse(); + } + }; + } + }; + HttpRequest httpRequest = + mockHttpTransport.createRequestFactory().buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL); + TestServiceOptions testServiceOptions = + TestServiceOptions.newBuilder() + .setCredentials(credentials) + .setHeaderProvider(headerProvider) + .setQuotaProjectId(DEFAULT_PROJECT_ID) + .setProjectId(DEFAULT_PROJECT_ID) + .setUniverseDomain("random.com") + .build(); + HttpRequestInitializer httpRequestInitializer = + DEFAULT_OPTIONS.getHttpRequestInitializer(testServiceOptions); + httpRequestInitializer.initialize(httpRequest); + } + + @Test + public void testHttpRequestInitializer_defaultUniverseDomain_noCredentials() throws IOException { NoCredentials credentials = NoCredentials.getInstance(); HeaderProvider headerProvider = EasyMock.createMock(HeaderProvider.class); EasyMock.expect(headerProvider.getHeaders()).andReturn(new HashMap<>()); @@ -312,11 +392,50 @@ public LowLevelHttpResponse execute() { TestServiceOptions.newBuilder() .setCredentials(credentials) .setHeaderProvider(headerProvider) - .setQuotaProjectId("testing") - .setProjectId("testing") + .setQuotaProjectId(DEFAULT_PROJECT_ID) + .setProjectId(DEFAULT_PROJECT_ID) .build(); HttpRequestInitializer httpRequestInitializer = DEFAULT_OPTIONS.getHttpRequestInitializer(testServiceOptions); httpRequestInitializer.initialize(httpRequest); } + + @Test + public void testHttpRequestInitializer_customUniverseDomain_noCredentials() throws IOException { + NoCredentials credentials = NoCredentials.getInstance(); + HeaderProvider headerProvider = EasyMock.createMock(HeaderProvider.class); + EasyMock.expect(headerProvider.getHeaders()).andReturn(new HashMap<>()); + EasyMock.replay(headerProvider); + + HttpTransport mockHttpTransport = + new MockHttpTransport() { + @Override + public LowLevelHttpRequest buildRequest(String method, String url) { + return new MockLowLevelHttpRequest() { + @Override + public LowLevelHttpResponse execute() { + return new MockLowLevelHttpResponse(); + } + }; + } + }; + HttpRequest httpRequest = + mockHttpTransport.createRequestFactory().buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL); + TestServiceOptions testServiceOptions = + TestServiceOptions.newBuilder() + .setCredentials(credentials) + .setHeaderProvider(headerProvider) + .setQuotaProjectId(DEFAULT_PROJECT_ID) + .setProjectId(DEFAULT_PROJECT_ID) + .setUniverseDomain("random.com") + .build(); + HttpRequestInitializer httpRequestInitializer = + DEFAULT_OPTIONS.getHttpRequestInitializer(testServiceOptions); + IllegalStateException exception = + assertThrows( + IllegalStateException.class, () -> httpRequestInitializer.initialize(httpRequest)); + assertEquals( + "The configured universe domain (random.com) does not match the universe domain found in the credentials (googleapis.com). If you haven't configured the universe domain explicitly, `googleapis.com` is the default.", + exception.getMessage()); + } } From 0b0016c226f4bdf153045d3e033c4db15933daf3 Mon Sep 17 00:00:00 2001 From: Lawrence Qiu Date: Wed, 3 Apr 2024 16:36:08 -0400 Subject: [PATCH 4/8] chore: Clean up tests --- .../cloud/http/HttpTransportOptions.java | 7 +- .../cloud/http/HttpTransportOptionsTest.java | 241 ++++++------------ 2 files changed, 75 insertions(+), 173 deletions(-) diff --git a/java-core/google-cloud-core-http/src/main/java/com/google/cloud/http/HttpTransportOptions.java b/java-core/google-cloud-core-http/src/main/java/com/google/cloud/http/HttpTransportOptions.java index cc2102ccc8..61ba077812 100644 --- a/java-core/google-cloud-core-http/src/main/java/com/google/cloud/http/HttpTransportOptions.java +++ b/java-core/google-cloud-core-http/src/main/java/com/google/cloud/http/HttpTransportOptions.java @@ -156,8 +156,9 @@ public HttpRequestInitializer getHttpRequestInitializer( return new HttpRequestInitializer() { /** - * Resolve the Universe Domain from ServiceOptions or the Environment Variable. Otherwise, - * resolve to the Google Default Universe. + * Helper method to resolve the Universe Domain. First checks the user configuration from + * ServiceOptions, then the Environment Variable. If both haven't been set, resolve the value + * to be the Google Default Universe. */ private String determineUniverseDomain() { String universeDomain = serviceOptions.getUniverseDomain(); @@ -170,7 +171,7 @@ private String determineUniverseDomain() { @Override public void initialize(HttpRequest httpRequest) throws IOException { String configuredUniverseDomain = determineUniverseDomain(); - // Default to the GDU and override with value in the Credentials + // Default to the GDU. Override with value in the Credentials if needed String credentialsUniverseDomain = Credentials.GOOGLE_DEFAULT_UNIVERSE; // delegate is always HttpCredentialsAdapter or null (NoCredentials) diff --git a/java-core/google-cloud-core-http/src/test/java/com/google/cloud/http/HttpTransportOptionsTest.java b/java-core/google-cloud-core-http/src/test/java/com/google/cloud/http/HttpTransportOptionsTest.java index 9307e72dde..657b85ab2b 100644 --- a/java-core/google-cloud-core-http/src/test/java/com/google/cloud/http/HttpTransportOptionsTest.java +++ b/java-core/google-cloud-core-http/src/test/java/com/google/cloud/http/HttpTransportOptionsTest.java @@ -49,9 +49,22 @@ import java.util.Set; import java.util.regex.Pattern; import org.easymock.EasyMock; +import org.junit.Before; import org.junit.Test; public class HttpTransportOptionsTest { + private static final HttpTransport MOCK_HTTP_TRANSPORT = + new MockHttpTransport() { + @Override + public LowLevelHttpRequest buildRequest(String method, String url) { + return new MockLowLevelHttpRequest() { + @Override + public LowLevelHttpResponse execute() { + return new MockLowLevelHttpResponse(); + } + }; + } + }; private static final HttpTransportFactory MOCK_HTTP_TRANSPORT_FACTORY = EasyMock.createMock(HttpTransportFactory.class); @@ -66,6 +79,13 @@ public class HttpTransportOptionsTest { private static final HttpTransportOptions OPTIONS_COPY = OPTIONS.toBuilder().build(); private static final String DEFAULT_PROJECT_ID = "testing"; + private HeaderProvider defaultHeaderProvider; + // Credentials' getUniverseDomain() returns GDU + private Credentials defaultGDUCredentials; + // Credentials' getUniverseDomain() returns `random.com` + private Credentials defaultCustomCredentials; + private HttpRequest defaultHttpRequest; + /** * The following interfaces and classes are from ServiceOptionsTest. Copied over here as * ServiceOptions resides inside google-cloud-core test folder and is not accessible from @@ -175,6 +195,26 @@ public int hashCode() { } } + @Before + public void setup() throws IOException { + defaultHeaderProvider = EasyMock.createMock(HeaderProvider.class); + EasyMock.expect(defaultHeaderProvider.getHeaders()).andReturn(new HashMap<>()); + + defaultGDUCredentials = EasyMock.createMock(Credentials.class); + EasyMock.expect(defaultGDUCredentials.getUniverseDomain()) + .andReturn(Credentials.GOOGLE_DEFAULT_UNIVERSE); + EasyMock.expect(defaultGDUCredentials.hasRequestMetadata()).andReturn(false); + + defaultCustomCredentials = EasyMock.createMock(Credentials.class); + EasyMock.expect(defaultCustomCredentials.getUniverseDomain()).andReturn("random.com"); + EasyMock.expect(defaultCustomCredentials.hasRequestMetadata()).andReturn(false); + + EasyMock.replay(defaultHeaderProvider, defaultGDUCredentials, defaultCustomCredentials); + + defaultHttpRequest = + MOCK_HTTP_TRANSPORT.createRequestFactory().buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL); + } + @Test public void testBuilder() { assertEquals(1234, OPTIONS.getConnectTimeout()); @@ -214,117 +254,39 @@ public void testHeader() { @Test public void testHttpRequestInitializer_defaultUniverseDomain_defaultCredentials() throws IOException { - Credentials credentials = EasyMock.createMock(Credentials.class); - EasyMock.expect(credentials.getUniverseDomain()).andReturn(Credentials.GOOGLE_DEFAULT_UNIVERSE); - EasyMock.expect(credentials.hasRequestMetadata()).andReturn(false); - HeaderProvider headerProvider = EasyMock.createMock(HeaderProvider.class); - EasyMock.expect(headerProvider.getHeaders()).andReturn(new HashMap<>()); - EasyMock.replay(credentials, headerProvider); - - HttpTransport mockHttpTransport = - new MockHttpTransport() { - @Override - public LowLevelHttpRequest buildRequest(String method, String url) { - return new MockLowLevelHttpRequest() { - @Override - public LowLevelHttpResponse execute() { - return new MockLowLevelHttpResponse(); - } - }; - } - }; - HttpRequest httpRequest = - mockHttpTransport.createRequestFactory().buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL); TestServiceOptions testServiceOptions = - TestServiceOptions.newBuilder() - .setCredentials(credentials) - .setHeaderProvider(headerProvider) - .setQuotaProjectId(DEFAULT_PROJECT_ID) - .setProjectId(DEFAULT_PROJECT_ID) - .build(); + generateTestServiceOptions(defaultGDUCredentials, Credentials.GOOGLE_DEFAULT_UNIVERSE); HttpRequestInitializer httpRequestInitializer = DEFAULT_OPTIONS.getHttpRequestInitializer(testServiceOptions); - httpRequestInitializer.initialize(httpRequest); + // Does not throw a validation exception + httpRequestInitializer.initialize(defaultHttpRequest); } @Test - public void testHttpRequestInitializer_defaultUniverseDomain_customCredentials() - throws IOException { - Credentials credentials = EasyMock.createMock(Credentials.class); - EasyMock.expect(credentials.getUniverseDomain()).andReturn("random.com"); - EasyMock.expect(credentials.hasRequestMetadata()).andReturn(false); - HeaderProvider headerProvider = EasyMock.createMock(HeaderProvider.class); - EasyMock.expect(headerProvider.getHeaders()).andReturn(new HashMap<>()); - EasyMock.replay(credentials, headerProvider); - - HttpTransport mockHttpTransport = - new MockHttpTransport() { - @Override - public LowLevelHttpRequest buildRequest(String method, String url) { - return new MockLowLevelHttpRequest() { - @Override - public LowLevelHttpResponse execute() { - return new MockLowLevelHttpResponse(); - } - }; - } - }; - HttpRequest httpRequest = - mockHttpTransport.createRequestFactory().buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL); + public void testHttpRequestInitializer_defaultUniverseDomain_customCredentials() { TestServiceOptions testServiceOptions = - TestServiceOptions.newBuilder() - .setCredentials(credentials) - .setHeaderProvider(headerProvider) - .setQuotaProjectId(DEFAULT_PROJECT_ID) - .setProjectId(DEFAULT_PROJECT_ID) - .build(); + generateTestServiceOptions(defaultCustomCredentials, Credentials.GOOGLE_DEFAULT_UNIVERSE); HttpRequestInitializer httpRequestInitializer = DEFAULT_OPTIONS.getHttpRequestInitializer(testServiceOptions); IllegalStateException exception = assertThrows( - IllegalStateException.class, () -> httpRequestInitializer.initialize(httpRequest)); + IllegalStateException.class, + () -> httpRequestInitializer.initialize(defaultHttpRequest)); assertEquals( "The configured universe domain (googleapis.com) does not match the universe domain found in the credentials (random.com). If you haven't configured the universe domain explicitly, `googleapis.com` is the default.", exception.getMessage()); } @Test - public void testHttpRequestInitializer_customUniverseDomain_defaultCredentials() - throws IOException { - Credentials credentials = EasyMock.createMock(Credentials.class); - EasyMock.expect(credentials.getUniverseDomain()).andReturn(Credentials.GOOGLE_DEFAULT_UNIVERSE); - EasyMock.expect(credentials.hasRequestMetadata()).andReturn(false); - HeaderProvider headerProvider = EasyMock.createMock(HeaderProvider.class); - EasyMock.expect(headerProvider.getHeaders()).andReturn(new HashMap<>()); - EasyMock.replay(credentials, headerProvider); - - HttpTransport mockHttpTransport = - new MockHttpTransport() { - @Override - public LowLevelHttpRequest buildRequest(String method, String url) { - return new MockLowLevelHttpRequest() { - @Override - public LowLevelHttpResponse execute() { - return new MockLowLevelHttpResponse(); - } - }; - } - }; - HttpRequest httpRequest = - mockHttpTransport.createRequestFactory().buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL); + public void testHttpRequestInitializer_customUniverseDomain_defaultCredentials() { TestServiceOptions testServiceOptions = - TestServiceOptions.newBuilder() - .setCredentials(credentials) - .setHeaderProvider(headerProvider) - .setQuotaProjectId(DEFAULT_PROJECT_ID) - .setProjectId(DEFAULT_PROJECT_ID) - .setUniverseDomain("random.com") - .build(); + generateTestServiceOptions(defaultGDUCredentials, "random.com"); HttpRequestInitializer httpRequestInitializer = DEFAULT_OPTIONS.getHttpRequestInitializer(testServiceOptions); IllegalStateException exception = assertThrows( - IllegalStateException.class, () -> httpRequestInitializer.initialize(httpRequest)); + IllegalStateException.class, + () -> httpRequestInitializer.initialize(defaultHttpRequest)); assertEquals( "The configured universe domain (random.com) does not match the universe domain found in the credentials (googleapis.com). If you haven't configured the universe domain explicitly, `googleapis.com` is the default.", exception.getMessage()); @@ -333,109 +295,48 @@ public LowLevelHttpResponse execute() { @Test public void testHttpRequestInitializer_customUniverseDomain_customCredentials() throws IOException { - Credentials credentials = EasyMock.createMock(Credentials.class); - EasyMock.expect(credentials.getUniverseDomain()).andReturn("random.com"); - EasyMock.expect(credentials.hasRequestMetadata()).andReturn(false); - HeaderProvider headerProvider = EasyMock.createMock(HeaderProvider.class); - EasyMock.expect(headerProvider.getHeaders()).andReturn(new HashMap<>()); - EasyMock.replay(credentials, headerProvider); - - HttpTransport mockHttpTransport = - new MockHttpTransport() { - @Override - public LowLevelHttpRequest buildRequest(String method, String url) { - return new MockLowLevelHttpRequest() { - @Override - public LowLevelHttpResponse execute() { - return new MockLowLevelHttpResponse(); - } - }; - } - }; - HttpRequest httpRequest = - mockHttpTransport.createRequestFactory().buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL); TestServiceOptions testServiceOptions = - TestServiceOptions.newBuilder() - .setCredentials(credentials) - .setHeaderProvider(headerProvider) - .setQuotaProjectId(DEFAULT_PROJECT_ID) - .setProjectId(DEFAULT_PROJECT_ID) - .setUniverseDomain("random.com") - .build(); + generateTestServiceOptions(defaultCustomCredentials, "random.com"); HttpRequestInitializer httpRequestInitializer = DEFAULT_OPTIONS.getHttpRequestInitializer(testServiceOptions); - httpRequestInitializer.initialize(httpRequest); + // Does not throw a validation exception + httpRequestInitializer.initialize(defaultHttpRequest); } @Test public void testHttpRequestInitializer_defaultUniverseDomain_noCredentials() throws IOException { NoCredentials credentials = NoCredentials.getInstance(); - HeaderProvider headerProvider = EasyMock.createMock(HeaderProvider.class); - EasyMock.expect(headerProvider.getHeaders()).andReturn(new HashMap<>()); - EasyMock.replay(headerProvider); - - HttpTransport mockHttpTransport = - new MockHttpTransport() { - @Override - public LowLevelHttpRequest buildRequest(String method, String url) { - return new MockLowLevelHttpRequest() { - @Override - public LowLevelHttpResponse execute() { - return new MockLowLevelHttpResponse(); - } - }; - } - }; - HttpRequest httpRequest = - mockHttpTransport.createRequestFactory().buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL); TestServiceOptions testServiceOptions = - TestServiceOptions.newBuilder() - .setCredentials(credentials) - .setHeaderProvider(headerProvider) - .setQuotaProjectId(DEFAULT_PROJECT_ID) - .setProjectId(DEFAULT_PROJECT_ID) - .build(); + generateTestServiceOptions(credentials, Credentials.GOOGLE_DEFAULT_UNIVERSE); HttpRequestInitializer httpRequestInitializer = DEFAULT_OPTIONS.getHttpRequestInitializer(testServiceOptions); - httpRequestInitializer.initialize(httpRequest); + // Does not throw a validation exception + httpRequestInitializer.initialize(defaultHttpRequest); } @Test public void testHttpRequestInitializer_customUniverseDomain_noCredentials() throws IOException { NoCredentials credentials = NoCredentials.getInstance(); - HeaderProvider headerProvider = EasyMock.createMock(HeaderProvider.class); - EasyMock.expect(headerProvider.getHeaders()).andReturn(new HashMap<>()); - EasyMock.replay(headerProvider); - - HttpTransport mockHttpTransport = - new MockHttpTransport() { - @Override - public LowLevelHttpRequest buildRequest(String method, String url) { - return new MockLowLevelHttpRequest() { - @Override - public LowLevelHttpResponse execute() { - return new MockLowLevelHttpResponse(); - } - }; - } - }; - HttpRequest httpRequest = - mockHttpTransport.createRequestFactory().buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL); - TestServiceOptions testServiceOptions = - TestServiceOptions.newBuilder() - .setCredentials(credentials) - .setHeaderProvider(headerProvider) - .setQuotaProjectId(DEFAULT_PROJECT_ID) - .setProjectId(DEFAULT_PROJECT_ID) - .setUniverseDomain("random.com") - .build(); + TestServiceOptions testServiceOptions = generateTestServiceOptions(credentials, "random.com"); HttpRequestInitializer httpRequestInitializer = DEFAULT_OPTIONS.getHttpRequestInitializer(testServiceOptions); IllegalStateException exception = assertThrows( - IllegalStateException.class, () -> httpRequestInitializer.initialize(httpRequest)); + IllegalStateException.class, + () -> httpRequestInitializer.initialize(defaultHttpRequest)); assertEquals( "The configured universe domain (random.com) does not match the universe domain found in the credentials (googleapis.com). If you haven't configured the universe domain explicitly, `googleapis.com` is the default.", exception.getMessage()); } + + private TestServiceOptions generateTestServiceOptions( + Credentials credentials, String universeDomain) { + return TestServiceOptions.newBuilder() + .setCredentials(credentials) + .setHeaderProvider(defaultHeaderProvider) + .setQuotaProjectId(DEFAULT_PROJECT_ID) + .setProjectId(DEFAULT_PROJECT_ID) + .setUniverseDomain(universeDomain) + .build(); + } } From b3304c603c9010ef54a2716fcadd228389c5b9aa Mon Sep 17 00:00:00 2001 From: Lawrence Qiu Date: Wed, 3 Apr 2024 16:57:28 -0400 Subject: [PATCH 5/8] chore: Clean up tests --- .../cloud/http/HttpTransportOptionsTest.java | 43 ++++++++++--------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/java-core/google-cloud-core-http/src/test/java/com/google/cloud/http/HttpTransportOptionsTest.java b/java-core/google-cloud-core-http/src/test/java/com/google/cloud/http/HttpTransportOptionsTest.java index 657b85ab2b..fd7d41d8f0 100644 --- a/java-core/google-cloud-core-http/src/test/java/com/google/cloud/http/HttpTransportOptionsTest.java +++ b/java-core/google-cloud-core-http/src/test/java/com/google/cloud/http/HttpTransportOptionsTest.java @@ -78,12 +78,13 @@ public LowLevelHttpResponse execute() { HttpTransportOptions.newBuilder().build(); private static final HttpTransportOptions OPTIONS_COPY = OPTIONS.toBuilder().build(); private static final String DEFAULT_PROJECT_ID = "testing"; + private static final String CUSTOM_UNIVERSE_DOMAIN = "random.com"; private HeaderProvider defaultHeaderProvider; // Credentials' getUniverseDomain() returns GDU - private Credentials defaultGDUCredentials; + private Credentials defaultCredentials; // Credentials' getUniverseDomain() returns `random.com` - private Credentials defaultCustomCredentials; + private Credentials customCredentials; private HttpRequest defaultHttpRequest; /** @@ -200,16 +201,16 @@ public void setup() throws IOException { defaultHeaderProvider = EasyMock.createMock(HeaderProvider.class); EasyMock.expect(defaultHeaderProvider.getHeaders()).andReturn(new HashMap<>()); - defaultGDUCredentials = EasyMock.createMock(Credentials.class); - EasyMock.expect(defaultGDUCredentials.getUniverseDomain()) + defaultCredentials = EasyMock.createMock(Credentials.class); + EasyMock.expect(defaultCredentials.getUniverseDomain()) .andReturn(Credentials.GOOGLE_DEFAULT_UNIVERSE); - EasyMock.expect(defaultGDUCredentials.hasRequestMetadata()).andReturn(false); + EasyMock.expect(defaultCredentials.hasRequestMetadata()).andReturn(false); - defaultCustomCredentials = EasyMock.createMock(Credentials.class); - EasyMock.expect(defaultCustomCredentials.getUniverseDomain()).andReturn("random.com"); - EasyMock.expect(defaultCustomCredentials.hasRequestMetadata()).andReturn(false); + customCredentials = EasyMock.createMock(Credentials.class); + EasyMock.expect(customCredentials.getUniverseDomain()).andReturn(CUSTOM_UNIVERSE_DOMAIN); + EasyMock.expect(customCredentials.hasRequestMetadata()).andReturn(false); - EasyMock.replay(defaultHeaderProvider, defaultGDUCredentials, defaultCustomCredentials); + EasyMock.replay(defaultHeaderProvider, defaultCredentials, customCredentials); defaultHttpRequest = MOCK_HTTP_TRANSPORT.createRequestFactory().buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL); @@ -252,10 +253,10 @@ public void testHeader() { } @Test - public void testHttpRequestInitializer_defaultUniverseDomain_defaultCredentials() + public void testHttpRequestInitializer_defaultUniverseDomainSettings_defaultCredentials() throws IOException { TestServiceOptions testServiceOptions = - generateTestServiceOptions(defaultGDUCredentials, Credentials.GOOGLE_DEFAULT_UNIVERSE); + generateTestServiceOptions(defaultCredentials, Credentials.GOOGLE_DEFAULT_UNIVERSE); HttpRequestInitializer httpRequestInitializer = DEFAULT_OPTIONS.getHttpRequestInitializer(testServiceOptions); // Does not throw a validation exception @@ -263,9 +264,9 @@ public void testHttpRequestInitializer_defaultUniverseDomain_defaultCredentials( } @Test - public void testHttpRequestInitializer_defaultUniverseDomain_customCredentials() { + public void testHttpRequestInitializer_defaultUniverseDomainSettings_customCredentials() { TestServiceOptions testServiceOptions = - generateTestServiceOptions(defaultCustomCredentials, Credentials.GOOGLE_DEFAULT_UNIVERSE); + generateTestServiceOptions(customCredentials, Credentials.GOOGLE_DEFAULT_UNIVERSE); HttpRequestInitializer httpRequestInitializer = DEFAULT_OPTIONS.getHttpRequestInitializer(testServiceOptions); IllegalStateException exception = @@ -278,9 +279,9 @@ public void testHttpRequestInitializer_defaultUniverseDomain_customCredentials() } @Test - public void testHttpRequestInitializer_customUniverseDomain_defaultCredentials() { + public void testHttpRequestInitializer_customUniverseDomainSettings_defaultCredentials() { TestServiceOptions testServiceOptions = - generateTestServiceOptions(defaultGDUCredentials, "random.com"); + generateTestServiceOptions(defaultCredentials, CUSTOM_UNIVERSE_DOMAIN); HttpRequestInitializer httpRequestInitializer = DEFAULT_OPTIONS.getHttpRequestInitializer(testServiceOptions); IllegalStateException exception = @@ -293,10 +294,10 @@ public void testHttpRequestInitializer_customUniverseDomain_defaultCredentials() } @Test - public void testHttpRequestInitializer_customUniverseDomain_customCredentials() + public void testHttpRequestInitializer_customUniverseDomainSettings_customCredentials() throws IOException { TestServiceOptions testServiceOptions = - generateTestServiceOptions(defaultCustomCredentials, "random.com"); + generateTestServiceOptions(customCredentials, CUSTOM_UNIVERSE_DOMAIN); HttpRequestInitializer httpRequestInitializer = DEFAULT_OPTIONS.getHttpRequestInitializer(testServiceOptions); // Does not throw a validation exception @@ -304,7 +305,8 @@ public void testHttpRequestInitializer_customUniverseDomain_customCredentials() } @Test - public void testHttpRequestInitializer_defaultUniverseDomain_noCredentials() throws IOException { + public void testHttpRequestInitializer_defaultUniverseDomainSettings_noCredentials() + throws IOException { NoCredentials credentials = NoCredentials.getInstance(); TestServiceOptions testServiceOptions = generateTestServiceOptions(credentials, Credentials.GOOGLE_DEFAULT_UNIVERSE); @@ -315,9 +317,10 @@ public void testHttpRequestInitializer_defaultUniverseDomain_noCredentials() thr } @Test - public void testHttpRequestInitializer_customUniverseDomain_noCredentials() throws IOException { + public void testHttpRequestInitializer_customUniverseDomainSettings_noCredentials() { NoCredentials credentials = NoCredentials.getInstance(); - TestServiceOptions testServiceOptions = generateTestServiceOptions(credentials, "random.com"); + TestServiceOptions testServiceOptions = + generateTestServiceOptions(credentials, CUSTOM_UNIVERSE_DOMAIN); HttpRequestInitializer httpRequestInitializer = DEFAULT_OPTIONS.getHttpRequestInitializer(testServiceOptions); IllegalStateException exception = From e62377a8ee7da5ec4975a3f162351b2fce1111db Mon Sep 17 00:00:00 2001 From: Lawrence Qiu Date: Wed, 3 Apr 2024 16:59:08 -0400 Subject: [PATCH 6/8] chore: Refactor helper method param order --- .../cloud/http/HttpTransportOptionsTest.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/java-core/google-cloud-core-http/src/test/java/com/google/cloud/http/HttpTransportOptionsTest.java b/java-core/google-cloud-core-http/src/test/java/com/google/cloud/http/HttpTransportOptionsTest.java index fd7d41d8f0..4c1168980d 100644 --- a/java-core/google-cloud-core-http/src/test/java/com/google/cloud/http/HttpTransportOptionsTest.java +++ b/java-core/google-cloud-core-http/src/test/java/com/google/cloud/http/HttpTransportOptionsTest.java @@ -256,7 +256,7 @@ public void testHeader() { public void testHttpRequestInitializer_defaultUniverseDomainSettings_defaultCredentials() throws IOException { TestServiceOptions testServiceOptions = - generateTestServiceOptions(defaultCredentials, Credentials.GOOGLE_DEFAULT_UNIVERSE); + generateTestServiceOptions(Credentials.GOOGLE_DEFAULT_UNIVERSE, defaultCredentials); HttpRequestInitializer httpRequestInitializer = DEFAULT_OPTIONS.getHttpRequestInitializer(testServiceOptions); // Does not throw a validation exception @@ -266,7 +266,7 @@ public void testHttpRequestInitializer_defaultUniverseDomainSettings_defaultCred @Test public void testHttpRequestInitializer_defaultUniverseDomainSettings_customCredentials() { TestServiceOptions testServiceOptions = - generateTestServiceOptions(customCredentials, Credentials.GOOGLE_DEFAULT_UNIVERSE); + generateTestServiceOptions(Credentials.GOOGLE_DEFAULT_UNIVERSE, customCredentials); HttpRequestInitializer httpRequestInitializer = DEFAULT_OPTIONS.getHttpRequestInitializer(testServiceOptions); IllegalStateException exception = @@ -281,7 +281,7 @@ public void testHttpRequestInitializer_defaultUniverseDomainSettings_customCrede @Test public void testHttpRequestInitializer_customUniverseDomainSettings_defaultCredentials() { TestServiceOptions testServiceOptions = - generateTestServiceOptions(defaultCredentials, CUSTOM_UNIVERSE_DOMAIN); + generateTestServiceOptions(CUSTOM_UNIVERSE_DOMAIN, defaultCredentials); HttpRequestInitializer httpRequestInitializer = DEFAULT_OPTIONS.getHttpRequestInitializer(testServiceOptions); IllegalStateException exception = @@ -297,7 +297,7 @@ public void testHttpRequestInitializer_customUniverseDomainSettings_defaultCrede public void testHttpRequestInitializer_customUniverseDomainSettings_customCredentials() throws IOException { TestServiceOptions testServiceOptions = - generateTestServiceOptions(customCredentials, CUSTOM_UNIVERSE_DOMAIN); + generateTestServiceOptions(CUSTOM_UNIVERSE_DOMAIN, customCredentials); HttpRequestInitializer httpRequestInitializer = DEFAULT_OPTIONS.getHttpRequestInitializer(testServiceOptions); // Does not throw a validation exception @@ -307,9 +307,9 @@ public void testHttpRequestInitializer_customUniverseDomainSettings_customCreden @Test public void testHttpRequestInitializer_defaultUniverseDomainSettings_noCredentials() throws IOException { - NoCredentials credentials = NoCredentials.getInstance(); + NoCredentials noCredentials = NoCredentials.getInstance(); TestServiceOptions testServiceOptions = - generateTestServiceOptions(credentials, Credentials.GOOGLE_DEFAULT_UNIVERSE); + generateTestServiceOptions(Credentials.GOOGLE_DEFAULT_UNIVERSE, noCredentials); HttpRequestInitializer httpRequestInitializer = DEFAULT_OPTIONS.getHttpRequestInitializer(testServiceOptions); // Does not throw a validation exception @@ -318,9 +318,9 @@ public void testHttpRequestInitializer_defaultUniverseDomainSettings_noCredentia @Test public void testHttpRequestInitializer_customUniverseDomainSettings_noCredentials() { - NoCredentials credentials = NoCredentials.getInstance(); + NoCredentials noCredentials = NoCredentials.getInstance(); TestServiceOptions testServiceOptions = - generateTestServiceOptions(credentials, CUSTOM_UNIVERSE_DOMAIN); + generateTestServiceOptions(CUSTOM_UNIVERSE_DOMAIN, noCredentials); HttpRequestInitializer httpRequestInitializer = DEFAULT_OPTIONS.getHttpRequestInitializer(testServiceOptions); IllegalStateException exception = @@ -333,7 +333,7 @@ public void testHttpRequestInitializer_customUniverseDomainSettings_noCredential } private TestServiceOptions generateTestServiceOptions( - Credentials credentials, String universeDomain) { + String universeDomain, Credentials credentials) { return TestServiceOptions.newBuilder() .setCredentials(credentials) .setHeaderProvider(defaultHeaderProvider) From f3f6462e92234c422ffd53d2559d372a6830f212 Mon Sep 17 00:00:00 2001 From: Lawrence Qiu Date: Fri, 12 Apr 2024 14:53:40 -0400 Subject: [PATCH 7/8] chore: Address PR comments --- .../java/com/google/api/gax/rpc/EndpointContext.java | 4 ++-- .../com/google/cloud/http/HttpTransportOptions.java | 11 +++++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java b/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java index c2f3ad50ab..de99b01995 100644 --- a/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java +++ b/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java @@ -47,8 +47,8 @@ @InternalApi @AutoValue public abstract class EndpointContext { - private static final String GOOGLE_CLOUD_UNIVERSE_DOMAIN = "GOOGLE_CLOUD_UNIVERSE_DOMAIN"; - private static final String INVALID_UNIVERSE_DOMAIN_ERROR_TEMPLATE = + public static final String GOOGLE_CLOUD_UNIVERSE_DOMAIN = "GOOGLE_CLOUD_UNIVERSE_DOMAIN"; + public static final String INVALID_UNIVERSE_DOMAIN_ERROR_TEMPLATE = "The configured universe domain (%s) does not match the universe domain found in the credentials (%s). If you haven't configured the universe domain explicitly, `googleapis.com` is the default."; public static final String UNABLE_TO_RETRIEVE_CREDENTIALS_ERROR_MESSAGE = "Unable to retrieve the Universe Domain from the Credentials."; diff --git a/java-core/google-cloud-core-http/src/main/java/com/google/cloud/http/HttpTransportOptions.java b/java-core/google-cloud-core-http/src/main/java/com/google/cloud/http/HttpTransportOptions.java index 61ba077812..55898bfaf9 100644 --- a/java-core/google-cloud-core-http/src/main/java/com/google/cloud/http/HttpTransportOptions.java +++ b/java-core/google-cloud-core-http/src/main/java/com/google/cloud/http/HttpTransportOptions.java @@ -26,6 +26,7 @@ import com.google.api.gax.core.GaxProperties; import com.google.api.gax.httpjson.HttpHeadersUtils; import com.google.api.gax.rpc.ApiClientHeaderProvider; +import com.google.api.gax.rpc.EndpointContext; import com.google.api.gax.rpc.HeaderProvider; import com.google.auth.Credentials; import com.google.auth.http.HttpCredentialsAdapter; @@ -42,7 +43,6 @@ public class HttpTransportOptions implements TransportOptions { private static final long serialVersionUID = 7890117765045419810L; - private static final String GOOGLE_CLOUD_UNIVERSE_DOMAIN = "GOOGLE_CLOUD_UNIVERSE_DOMAIN"; private final int connectTimeout; private final int readTimeout; private final String httpTransportFactoryClassName; @@ -163,7 +163,7 @@ public HttpRequestInitializer getHttpRequestInitializer( private String determineUniverseDomain() { String universeDomain = serviceOptions.getUniverseDomain(); if (universeDomain == null) { - universeDomain = System.getenv(GOOGLE_CLOUD_UNIVERSE_DOMAIN); + universeDomain = System.getenv(EndpointContext.GOOGLE_CLOUD_UNIVERSE_DOMAIN); } return universeDomain == null ? Credentials.GOOGLE_DEFAULT_UNIVERSE : universeDomain; } @@ -184,10 +184,9 @@ public void initialize(HttpRequest httpRequest) throws IOException { if (!configuredUniverseDomain.equals(credentialsUniverseDomain)) { throw new IllegalStateException( String.format( - "The configured universe domain (%s) does not match the universe domain found" - + " in the credentials (%s). If you haven't configured the universe domain" - + " explicitly, `googleapis.com` is the default.", - configuredUniverseDomain, credentialsUniverseDomain)); + EndpointContext.INVALID_UNIVERSE_DOMAIN_ERROR_TEMPLATE, + configuredUniverseDomain, + credentialsUniverseDomain)); } if (delegate != null) { From 35988a591acc96e317cf8cd0790573c4eecce708 Mon Sep 17 00:00:00 2001 From: Lawrence Qiu Date: Fri, 12 Apr 2024 15:29:27 -0400 Subject: [PATCH 8/8] chore: Address PR comments --- .../cloud/http/HttpTransportOptions.java | 16 +- .../cloud/http/HttpTransportOptionsTest.java | 237 +++++++++--------- 2 files changed, 130 insertions(+), 123 deletions(-) diff --git a/java-core/google-cloud-core-http/src/main/java/com/google/cloud/http/HttpTransportOptions.java b/java-core/google-cloud-core-http/src/main/java/com/google/cloud/http/HttpTransportOptions.java index 55898bfaf9..f5ad54532f 100644 --- a/java-core/google-cloud-core-http/src/main/java/com/google/cloud/http/HttpTransportOptions.java +++ b/java-core/google-cloud-core-http/src/main/java/com/google/cloud/http/HttpTransportOptions.java @@ -25,9 +25,12 @@ import com.google.api.client.http.javanet.NetHttpTransport; import com.google.api.gax.core.GaxProperties; import com.google.api.gax.httpjson.HttpHeadersUtils; +import com.google.api.gax.httpjson.HttpJsonStatusCode; import com.google.api.gax.rpc.ApiClientHeaderProvider; import com.google.api.gax.rpc.EndpointContext; import com.google.api.gax.rpc.HeaderProvider; +import com.google.api.gax.rpc.StatusCode; +import com.google.api.gax.rpc.UnauthenticatedException; import com.google.auth.Credentials; import com.google.auth.http.HttpCredentialsAdapter; import com.google.auth.http.HttpTransportFactory; @@ -182,11 +185,14 @@ public void initialize(HttpRequest httpRequest) throws IOException { // Validate the universe domain before initializing the request if (!configuredUniverseDomain.equals(credentialsUniverseDomain)) { - throw new IllegalStateException( - String.format( - EndpointContext.INVALID_UNIVERSE_DOMAIN_ERROR_TEMPLATE, - configuredUniverseDomain, - credentialsUniverseDomain)); + throw new UnauthenticatedException( + new Throwable( + String.format( + EndpointContext.INVALID_UNIVERSE_DOMAIN_ERROR_TEMPLATE, + configuredUniverseDomain, + credentialsUniverseDomain)), + HttpJsonStatusCode.of(StatusCode.Code.UNAUTHENTICATED), + false); } if (delegate != null) { diff --git a/java-core/google-cloud-core-http/src/test/java/com/google/cloud/http/HttpTransportOptionsTest.java b/java-core/google-cloud-core-http/src/test/java/com/google/cloud/http/HttpTransportOptionsTest.java index 4c1168980d..75ffc2bf17 100644 --- a/java-core/google-cloud-core-http/src/test/java/com/google/cloud/http/HttpTransportOptionsTest.java +++ b/java-core/google-cloud-core-http/src/test/java/com/google/cloud/http/HttpTransportOptionsTest.java @@ -32,6 +32,7 @@ import com.google.api.client.testing.http.MockLowLevelHttpRequest; import com.google.api.client.testing.http.MockLowLevelHttpResponse; import com.google.api.gax.rpc.HeaderProvider; +import com.google.api.gax.rpc.UnauthenticatedException; import com.google.auth.Credentials; import com.google.auth.http.HttpTransportFactory; import com.google.cloud.BaseService; @@ -87,115 +88,6 @@ public LowLevelHttpResponse execute() { private Credentials customCredentials; private HttpRequest defaultHttpRequest; - /** - * The following interfaces and classes are from ServiceOptionsTest. Copied over here as - * ServiceOptions resides inside google-cloud-core test folder and is not accessible from - * google-cloud-core-http. - */ - interface TestService extends Service {} - - private static class TestServiceImpl extends BaseService - implements TestService { - private TestServiceImpl(TestServiceOptions options) { - super(options); - } - } - - public interface TestServiceFactory extends ServiceFactory {} - - private static class DefaultTestServiceFactory implements TestServiceFactory { - private static final TestServiceFactory INSTANCE = new DefaultTestServiceFactory(); - - @Override - public TestService create(TestServiceOptions options) { - return new TestServiceImpl(options); - } - } - - public interface TestServiceRpcFactory extends ServiceRpcFactory {} - - private static class DefaultTestServiceRpcFactory implements TestServiceRpcFactory { - private static final TestServiceRpcFactory INSTANCE = new DefaultTestServiceRpcFactory(); - - @Override - public TestServiceRpc create(TestServiceOptions options) { - return new DefaultTestServiceRpc(options); - } - } - - private interface TestServiceRpc extends ServiceRpc {} - - private static class DefaultTestServiceRpc implements TestServiceRpc { - DefaultTestServiceRpc(TestServiceOptions options) {} - } - - static class TestServiceOptions extends ServiceOptions { - private static class Builder - extends ServiceOptions.Builder { - private Builder() {} - - private Builder(TestServiceOptions options) { - super(options); - } - - @Override - protected TestServiceOptions build() { - return new TestServiceOptions(this); - } - } - - private TestServiceOptions(Builder builder) { - super( - TestServiceFactory.class, - TestServiceRpcFactory.class, - builder, - new TestServiceDefaults()); - } - - private static class TestServiceDefaults - implements ServiceDefaults { - - @Override - public TestServiceFactory getDefaultServiceFactory() { - return DefaultTestServiceFactory.INSTANCE; - } - - @Override - public TestServiceRpcFactory getDefaultRpcFactory() { - return DefaultTestServiceRpcFactory.INSTANCE; - } - - @Override - public TransportOptions getDefaultTransportOptions() { - return new TransportOptions() {}; - } - } - - @Override - protected Set getScopes() { - return null; - } - - @Override - public Builder toBuilder() { - return new Builder(this); - } - - private static Builder newBuilder() { - return new Builder(); - } - - @Override - public boolean equals(Object obj) { - return obj instanceof TestServiceOptions && baseEquals((TestServiceOptions) obj); - } - - @Override - public int hashCode() { - return baseHashCode(); - } - } - @Before public void setup() throws IOException { defaultHeaderProvider = EasyMock.createMock(HeaderProvider.class); @@ -269,13 +161,13 @@ public void testHttpRequestInitializer_defaultUniverseDomainSettings_customCrede generateTestServiceOptions(Credentials.GOOGLE_DEFAULT_UNIVERSE, customCredentials); HttpRequestInitializer httpRequestInitializer = DEFAULT_OPTIONS.getHttpRequestInitializer(testServiceOptions); - IllegalStateException exception = + UnauthenticatedException exception = assertThrows( - IllegalStateException.class, + UnauthenticatedException.class, () -> httpRequestInitializer.initialize(defaultHttpRequest)); assertEquals( "The configured universe domain (googleapis.com) does not match the universe domain found in the credentials (random.com). If you haven't configured the universe domain explicitly, `googleapis.com` is the default.", - exception.getMessage()); + exception.getCause().getMessage()); } @Test @@ -284,13 +176,13 @@ public void testHttpRequestInitializer_customUniverseDomainSettings_defaultCrede generateTestServiceOptions(CUSTOM_UNIVERSE_DOMAIN, defaultCredentials); HttpRequestInitializer httpRequestInitializer = DEFAULT_OPTIONS.getHttpRequestInitializer(testServiceOptions); - IllegalStateException exception = + UnauthenticatedException exception = assertThrows( - IllegalStateException.class, + UnauthenticatedException.class, () -> httpRequestInitializer.initialize(defaultHttpRequest)); assertEquals( "The configured universe domain (random.com) does not match the universe domain found in the credentials (googleapis.com). If you haven't configured the universe domain explicitly, `googleapis.com` is the default.", - exception.getMessage()); + exception.getCause().getMessage()); } @Test @@ -323,13 +215,13 @@ public void testHttpRequestInitializer_customUniverseDomainSettings_noCredential generateTestServiceOptions(CUSTOM_UNIVERSE_DOMAIN, noCredentials); HttpRequestInitializer httpRequestInitializer = DEFAULT_OPTIONS.getHttpRequestInitializer(testServiceOptions); - IllegalStateException exception = + UnauthenticatedException exception = assertThrows( - IllegalStateException.class, + UnauthenticatedException.class, () -> httpRequestInitializer.initialize(defaultHttpRequest)); assertEquals( "The configured universe domain (random.com) does not match the universe domain found in the credentials (googleapis.com). If you haven't configured the universe domain explicitly, `googleapis.com` is the default.", - exception.getMessage()); + exception.getCause().getMessage()); } private TestServiceOptions generateTestServiceOptions( @@ -342,4 +234,113 @@ private TestServiceOptions generateTestServiceOptions( .setUniverseDomain(universeDomain) .build(); } + + /** + * The following interfaces and classes are from ServiceOptionsTest. Copied over here as + * ServiceOptions resides inside google-cloud-core test folder and is not accessible from + * google-cloud-core-http. + */ + interface TestService extends Service {} + + private static class TestServiceImpl extends BaseService + implements TestService { + private TestServiceImpl(TestServiceOptions options) { + super(options); + } + } + + public interface TestServiceFactory extends ServiceFactory {} + + private static class DefaultTestServiceFactory implements TestServiceFactory { + private static final TestServiceFactory INSTANCE = new DefaultTestServiceFactory(); + + @Override + public TestService create(TestServiceOptions options) { + return new TestServiceImpl(options); + } + } + + public interface TestServiceRpcFactory extends ServiceRpcFactory {} + + private static class DefaultTestServiceRpcFactory implements TestServiceRpcFactory { + private static final TestServiceRpcFactory INSTANCE = new DefaultTestServiceRpcFactory(); + + @Override + public TestServiceRpc create(TestServiceOptions options) { + return new DefaultTestServiceRpc(options); + } + } + + private interface TestServiceRpc extends ServiceRpc {} + + private static class DefaultTestServiceRpc implements TestServiceRpc { + DefaultTestServiceRpc(TestServiceOptions options) {} + } + + static class TestServiceOptions extends ServiceOptions { + private static class Builder + extends ServiceOptions.Builder { + private Builder() {} + + private Builder(TestServiceOptions options) { + super(options); + } + + @Override + protected TestServiceOptions build() { + return new TestServiceOptions(this); + } + } + + private TestServiceOptions(Builder builder) { + super( + TestServiceFactory.class, + TestServiceRpcFactory.class, + builder, + new TestServiceDefaults()); + } + + private static class TestServiceDefaults + implements ServiceDefaults { + + @Override + public TestServiceFactory getDefaultServiceFactory() { + return DefaultTestServiceFactory.INSTANCE; + } + + @Override + public TestServiceRpcFactory getDefaultRpcFactory() { + return DefaultTestServiceRpcFactory.INSTANCE; + } + + @Override + public TransportOptions getDefaultTransportOptions() { + return new TransportOptions() {}; + } + } + + @Override + protected Set getScopes() { + return null; + } + + @Override + public Builder toBuilder() { + return new Builder(this); + } + + private static Builder newBuilder() { + return new Builder(); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof TestServiceOptions && baseEquals((TestServiceOptions) obj); + } + + @Override + public int hashCode() { + return baseHashCode(); + } + } }