Skip to content

Commit 9c19934

Browse files
fix: respect SPANNER_EMULATOR_HOST env var when autoConfigEmulator=true (#2730)
* fix: respect SPANNER_EMULATOR_HOST env var when autoConfigEmulator=true The Connection API would always use the default emulator host when autoConfigEmulator=true was set in the connection string. This makes it harder to override the host name for the emulator when you also want the emulator to automatically create the instance and database that you connect to, as the only way to set it is to add it to the connection string. * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --------- Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
1 parent 7e142ff commit 9c19934

File tree

3 files changed

+125
-9
lines changed

3 files changed

+125
-9
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,20 +50,20 @@ If you are using Maven without the BOM, add this to your dependencies:
5050
If you are using Gradle 5.x or later, add this to your dependencies:
5151

5252
```Groovy
53-
implementation platform('com.google.cloud:libraries-bom:26.26.0')
53+
implementation platform('com.google.cloud:libraries-bom:26.27.0')
5454
5555
implementation 'com.google.cloud:google-cloud-spanner'
5656
```
5757
If you are using Gradle without BOM, add this to your dependencies:
5858

5959
```Groovy
60-
implementation 'com.google.cloud:google-cloud-spanner:6.52.1'
60+
implementation 'com.google.cloud:google-cloud-spanner:6.53.0'
6161
```
6262

6363
If you are using SBT, add this to your dependencies:
6464

6565
```Scala
66-
libraryDependencies += "com.google.cloud" % "google-cloud-spanner" % "6.52.1"
66+
libraryDependencies += "com.google.cloud" % "google-cloud-spanner" % "6.53.0"
6767
```
6868
<!-- {x-version-update-end} -->
6969

@@ -432,7 +432,7 @@ Java is a registered trademark of Oracle and/or its affiliates.
432432
[kokoro-badge-link-5]: http://storage.googleapis.com/cloud-devrel-public/java/badges/java-spanner/java11.html
433433
[stability-image]: https://img.shields.io/badge/stability-stable-green
434434
[maven-version-image]: https://img.shields.io/maven-central/v/com.google.cloud/google-cloud-spanner.svg
435-
[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-spanner/6.52.1
435+
[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-spanner/6.53.0
436436
[authentication]: https://github.com/googleapis/google-cloud-java#authentication
437437
[auth-scopes]: https://developers.google.com/identity/protocols/oauth2/scopes
438438
[predefined-iam-roles]: https://cloud.google.com/iam/docs/understanding-roles#predefined_roles

google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import java.util.Collections;
4949
import java.util.HashSet;
5050
import java.util.List;
51+
import java.util.Map;
5152
import java.util.Objects;
5253
import java.util.Set;
5354
import java.util.regex.Matcher;
@@ -191,6 +192,7 @@ public String[] getValidValues() {
191192
private static final String PLAIN_TEXT_PROTOCOL = "http:";
192193
private static final String HOST_PROTOCOL = "https:";
193194
private static final String DEFAULT_HOST = "https://spanner.googleapis.com";
195+
private static final String SPANNER_EMULATOR_HOST_ENV_VAR = "SPANNER_EMULATOR_HOST";
194196
private static final String DEFAULT_EMULATOR_HOST = "http://localhost:9010";
195197
/** Use plain text is only for local testing purposes. */
196198
private static final String USE_PLAIN_TEXT_PROPERTY_NAME = "usePlainText";
@@ -473,7 +475,10 @@ private Builder() {}
473475
"(?:cloudspanner:)(?<HOSTGROUP>//[\\w.-]+(?:\\.[\\w\\.-]+)*[\\w\\-\\._~:/?#\\[\\]@!\\$&'\\(\\)\\*\\+,;=.]+)?/projects/(?<PROJECTGROUP>(([a-z]|[-.:]|[0-9])+|(DEFAULT_PROJECT_ID)))(/instances/(?<INSTANCEGROUP>([a-z]|[-]|[0-9])+)(/databases/(?<DATABASEGROUP>([a-z]|[-]|[_]|[0-9])+))?)?(?:[?|;].*)?";
474476

475477
private static final String SPANNER_URI_REGEX = "(?is)^" + SPANNER_URI_FORMAT + "$";
476-
private static final Pattern SPANNER_URI_PATTERN = Pattern.compile(SPANNER_URI_REGEX);
478+
479+
@VisibleForTesting
480+
static final Pattern SPANNER_URI_PATTERN = Pattern.compile(SPANNER_URI_REGEX);
481+
477482
private static final String HOST_GROUP = "HOSTGROUP";
478483
private static final String PROJECT_GROUP = "PROJECTGROUP";
479484
private static final String INSTANCE_GROUP = "INSTANCEGROUP";
@@ -706,7 +711,7 @@ private ConnectionOptions(Builder builder) {
706711
this.autoConfigEmulator = parseAutoConfigEmulator(this.uri);
707712
this.dialect = parseDialect(this.uri);
708713
this.usePlainText = this.autoConfigEmulator || parseUsePlainText(this.uri);
709-
this.host = determineHost(matcher, autoConfigEmulator, usePlainText);
714+
this.host = determineHost(matcher, autoConfigEmulator, usePlainText, System.getenv());
710715
this.rpcPriority = parseRPCPriority(this.uri);
711716
this.delayTransactionStartUntilFirstWrite = parseDelayTransactionStartUntilFirstWrite(this.uri);
712717
this.trackSessionLeaks = parseTrackSessionLeaks(this.uri);
@@ -791,11 +796,19 @@ private ConnectionOptions(Builder builder) {
791796
}
792797
}
793798

794-
private static String determineHost(
795-
Matcher matcher, boolean autoConfigEmulator, boolean usePlainText) {
799+
@VisibleForTesting
800+
static String determineHost(
801+
Matcher matcher,
802+
boolean autoConfigEmulator,
803+
boolean usePlainText,
804+
Map<String, String> environment) {
796805
if (matcher.group(Builder.HOST_GROUP) == null) {
797806
if (autoConfigEmulator) {
798-
return DEFAULT_EMULATOR_HOST;
807+
if (Strings.isNullOrEmpty(environment.get(SPANNER_EMULATOR_HOST_ENV_VAR))) {
808+
return DEFAULT_EMULATOR_HOST;
809+
} else {
810+
return PLAIN_TEXT_PROTOCOL + "//" + environment.get(SPANNER_EMULATOR_HOST_ENV_VAR);
811+
}
799812
} else {
800813
return DEFAULT_HOST;
801814
}

google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionOptionsTest.java

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package com.google.cloud.spanner.connection;
1818

19+
import static com.google.cloud.spanner.connection.ConnectionOptions.Builder.SPANNER_URI_PATTERN;
20+
import static com.google.cloud.spanner.connection.ConnectionOptions.determineHost;
1921
import static com.google.common.truth.Truth.assertThat;
2022
import static org.junit.Assert.assertEquals;
2123
import static org.junit.Assert.assertFalse;
@@ -33,13 +35,15 @@
3335
import com.google.cloud.spanner.ErrorCode;
3436
import com.google.cloud.spanner.SpannerException;
3537
import com.google.cloud.spanner.SpannerOptions;
38+
import com.google.common.collect.ImmutableMap;
3639
import com.google.common.io.BaseEncoding;
3740
import com.google.common.io.Files;
3841
import java.io.File;
3942
import java.nio.charset.StandardCharsets;
4043
import java.util.Arrays;
4144
import java.util.Collections;
4245
import java.util.Objects;
46+
import java.util.regex.Matcher;
4347
import org.junit.Test;
4448
import org.junit.function.ThrowingRunnable;
4549
import org.junit.runner.RunWith;
@@ -153,6 +157,105 @@ public void testBuildWithAutoConfigEmulator() {
153157
assertTrue(options.isUsePlainText());
154158
}
155159

160+
@Test
161+
public void testDetermineHost() {
162+
final String uriWithoutHost =
163+
"cloudspanner:/projects/test-project-123/instances/test-instance-123/databases/test-database-123";
164+
Matcher matcherWithoutHost = SPANNER_URI_PATTERN.matcher(uriWithoutHost);
165+
assertTrue(matcherWithoutHost.find());
166+
final String uriWithHost =
167+
"cloudspanner://custom.host.domain:1234/projects/test-project-123/instances/test-instance-123/databases/test-database-123";
168+
Matcher matcherWithHost = SPANNER_URI_PATTERN.matcher(uriWithHost);
169+
assertTrue(matcherWithHost.find());
170+
171+
assertEquals(
172+
DEFAULT_HOST,
173+
determineHost(
174+
matcherWithoutHost,
175+
/* autoConfigEmulator= */ false,
176+
/* usePlainText= */ false,
177+
ImmutableMap.of()));
178+
assertEquals(
179+
DEFAULT_HOST,
180+
determineHost(
181+
matcherWithoutHost,
182+
/* autoConfigEmulator= */ false,
183+
/* usePlainText= */ false,
184+
ImmutableMap.of("FOO", "bar")));
185+
assertEquals(
186+
"http://localhost:9010",
187+
determineHost(
188+
matcherWithoutHost,
189+
/* autoConfigEmulator= */ true,
190+
/* usePlainText= */ false,
191+
ImmutableMap.of()));
192+
assertEquals(
193+
"http://localhost:9011",
194+
determineHost(
195+
matcherWithoutHost,
196+
/* autoConfigEmulator= */ true,
197+
/* usePlainText= */ false,
198+
ImmutableMap.of("SPANNER_EMULATOR_HOST", "localhost:9011")));
199+
assertEquals(
200+
"http://localhost:9010",
201+
determineHost(
202+
matcherWithoutHost,
203+
/* autoConfigEmulator= */ true,
204+
/* usePlainText= */ true,
205+
ImmutableMap.of()));
206+
assertEquals(
207+
"http://localhost:9011",
208+
determineHost(
209+
matcherWithoutHost,
210+
/* autoConfigEmulator= */ true,
211+
/* usePlainText= */ true,
212+
ImmutableMap.of("SPANNER_EMULATOR_HOST", "localhost:9011")));
213+
214+
// A host in the connection string has precedence over all other options.
215+
assertEquals(
216+
"https://custom.host.domain:1234",
217+
determineHost(
218+
matcherWithHost,
219+
/* autoConfigEmulator= */ false,
220+
/* usePlainText= */ false,
221+
ImmutableMap.of()));
222+
assertEquals(
223+
"http://custom.host.domain:1234",
224+
determineHost(
225+
matcherWithHost,
226+
/* autoConfigEmulator= */ false,
227+
/* usePlainText= */ true,
228+
ImmutableMap.of()));
229+
assertEquals(
230+
"http://custom.host.domain:1234",
231+
determineHost(
232+
matcherWithHost,
233+
/* autoConfigEmulator= */ false,
234+
/* usePlainText= */ true,
235+
ImmutableMap.of()));
236+
assertEquals(
237+
"https://custom.host.domain:1234",
238+
determineHost(
239+
matcherWithHost,
240+
/* autoConfigEmulator= */ true,
241+
/* usePlainText= */ false,
242+
ImmutableMap.of()));
243+
assertEquals(
244+
"http://custom.host.domain:1234",
245+
determineHost(
246+
matcherWithHost,
247+
/* autoConfigEmulator= */ false,
248+
/* usePlainText= */ true,
249+
ImmutableMap.of("SPANNER_EMULATOR_HOST", "localhost:9011")));
250+
assertEquals(
251+
"https://custom.host.domain:1234",
252+
determineHost(
253+
matcherWithHost,
254+
/* autoConfigEmulator= */ true,
255+
/* usePlainText= */ false,
256+
ImmutableMap.of("SPANNER_EMULATOR_HOST", "localhost:9011")));
257+
}
258+
156259
@Test
157260
public void testBuildWithRouteToLeader() {
158261
final String BASE_URI =

0 commit comments

Comments
 (0)