From 9f2678568be77e82c14632b1c7ffcaafb71e7679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Fri, 18 Sep 2020 08:43:49 +0200 Subject: [PATCH 01/19] fix: improve numeric range checks (#424) * fix: improve numeric range checks * fix: skip numeric ITs on emulator --- .../java/com/google/cloud/spanner/Value.java | 28 ++++++- .../cloud/spanner/GrpcResultSetTest.java | 18 +++- .../com/google/cloud/spanner/ValueTest.java | 81 ++++++++++++++++++ .../google/cloud/spanner/it/ITQueryTest.java | 83 ++++++++++++++++++- 4 files changed, 204 insertions(+), 6 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Value.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Value.java index fa0224ff950..5ea25908a8a 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Value.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Value.java @@ -123,11 +123,37 @@ public static Value float64(double v) { } /** - * Returns a {@code NUMERIC} value. + * Returns a {@code NUMERIC} value. The valid value range for the whole component of the {@link + * BigDecimal} is from -9,999,999,999,999,999,999,999,999 to +9,999,999,999,999,999,999,999,999 + * (both inclusive), i.e. the max length of the whole component is 29 digits. The max length of + * the fractional part is 9 digits. Trailing zeros in the fractional part are not considered and + * will be lost, as Cloud Spanner does not preserve the precision of a numeric value. + * + *

If you set a numeric value of a record to for example 0.10, Cloud Spanner will return this + * value as 0.1 in subsequent queries. Use {@link BigDecimal#stripTrailingZeros()} to compare + * inserted values with retrieved values if your application might insert numeric values with + * trailing zeros. * * @param v the value, which may be null */ public static Value numeric(@Nullable BigDecimal v) { + if (v != null) { + // Cloud Spanner does not preserve the precision, so 0.1 is considered equal to 0.10. + BigDecimal test = v.stripTrailingZeros(); + if (test.scale() > 9) { + throw SpannerExceptionFactory.newSpannerException( + ErrorCode.OUT_OF_RANGE, + String.format( + "Max scale for a numeric is 9. The requested numeric has scale %d", test.scale())); + } + if (test.precision() - test.scale() > 29) { + throw SpannerExceptionFactory.newSpannerException( + ErrorCode.OUT_OF_RANGE, + String.format( + "Max precision for the whole component of a numeric is 29. The requested numeric has a whole component with precision %d", + test.precision() - test.scale())); + } + } return new NumericImpl(v == null, v); } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/GrpcResultSetTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/GrpcResultSetTest.java index 4952e179adb..de1cb74c822 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/GrpcResultSetTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/GrpcResultSetTest.java @@ -25,6 +25,7 @@ import com.google.cloud.Timestamp; import com.google.cloud.spanner.spi.v1.SpannerRpc; import com.google.common.base.Function; +import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.protobuf.ByteString; @@ -692,17 +693,26 @@ public void getBigDecimal() { consumer.onPartialResultSet( PartialResultSet.newBuilder() .setMetadata(makeMetadata(Type.struct(Type.StructField.of("f", Type.numeric())))) - .addValues(Value.numeric(BigDecimal.valueOf(Double.MIN_VALUE)).toProto()) - .addValues(Value.numeric(BigDecimal.valueOf(Double.MAX_VALUE)).toProto()) + .addValues( + Value.numeric( + new BigDecimal( + "-" + Strings.repeat("9", 29) + "." + Strings.repeat("9", 9))) + .toProto()) + .addValues( + Value.numeric( + new BigDecimal(Strings.repeat("9", 29) + "." + Strings.repeat("9", 9))) + .toProto()) .addValues(Value.numeric(BigDecimal.ZERO).toProto()) .addValues(Value.numeric(new BigDecimal("1.23456")).toProto()) .build()); consumer.onCompleted(); assertThat(resultSet.next()).isTrue(); - assertThat(resultSet.getBigDecimal(0).doubleValue()).isWithin(0.0).of(Double.MIN_VALUE); + assertThat(resultSet.getBigDecimal(0).toPlainString()) + .isEqualTo("-99999999999999999999999999999.999999999"); assertThat(resultSet.next()).isTrue(); - assertThat(resultSet.getBigDecimal(0).doubleValue()).isWithin(0.0).of(Double.MAX_VALUE); + assertThat(resultSet.getBigDecimal(0).toPlainString()) + .isEqualTo("99999999999999999999999999999.999999999"); assertThat(resultSet.next()).isTrue(); assertThat(resultSet.getBigDecimal(0)).isEqualTo(BigDecimal.ZERO); assertThat(resultSet.next()).isTrue(); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ValueTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ValueTest.java index 0288f177af5..72222f72d01 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ValueTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ValueTest.java @@ -25,6 +25,7 @@ import com.google.cloud.Date; import com.google.cloud.Timestamp; import com.google.cloud.spanner.Type.StructField; +import com.google.common.base.Strings; import com.google.common.collect.ForwardingList; import com.google.common.collect.Lists; import com.google.common.testing.EqualsTester; @@ -265,6 +266,86 @@ public void testNumericFormats() { assertThat(new BigDecimal("1e-01").toString()).isEqualTo("0.1"); } + @Test + public void numericPrecisionAndScale() { + for (long s : new long[] {1L, -1L}) { + BigDecimal sign = new BigDecimal(s); + assertThat(Value.numeric(new BigDecimal(Strings.repeat("9", 29)).multiply(sign)).toString()) + .isEqualTo((s == -1L ? "-" : "") + Strings.repeat("9", 29)); + try { + Value.numeric(new BigDecimal(Strings.repeat("9", 30)).multiply(sign)); + fail("Missing expected exception"); + } catch (SpannerException e) { + assertThat(e.getErrorCode()).isEqualTo(ErrorCode.OUT_OF_RANGE); + } + try { + Value.numeric(new BigDecimal("1" + Strings.repeat("0", 29)).multiply(sign)); + fail("Missing expected exception"); + } catch (SpannerException e) { + assertThat(e.getErrorCode()).isEqualTo(ErrorCode.OUT_OF_RANGE); + } + + assertThat( + Value.numeric(new BigDecimal("0." + Strings.repeat("9", 9)).multiply(sign)) + .toString()) + .isEqualTo((s == -1L ? "-" : "") + "0." + Strings.repeat("9", 9)); + assertThat( + Value.numeric(new BigDecimal("0.1" + Strings.repeat("0", 8)).multiply(sign)) + .toString()) + .isEqualTo((s == -1L ? "-" : "") + "0.1" + Strings.repeat("0", 8)); + // Cloud Spanner does not store precision and considers 0.1 to be equal to 0.10. + // 0.100000000000000000000000000 is therefore also a valid value, as it will be capped to 0.1. + assertThat( + Value.numeric(new BigDecimal("0.1" + Strings.repeat("0", 20)).multiply(sign)) + .toString()) + .isEqualTo((s == -1L ? "-" : "") + "0.1" + Strings.repeat("0", 20)); + try { + Value.numeric(new BigDecimal("0." + Strings.repeat("9", 10)).multiply(sign)); + fail("Missing expected exception"); + } catch (SpannerException e) { + assertThat(e.getErrorCode()).isEqualTo(ErrorCode.OUT_OF_RANGE); + } + + assertThat( + Value.numeric( + new BigDecimal(Strings.repeat("9", 29) + "." + Strings.repeat("9", 9)) + .multiply(sign)) + .toString()) + .isEqualTo( + (s == -1L ? "-" : "") + Strings.repeat("9", 29) + "." + Strings.repeat("9", 9)); + + try { + Value.numeric( + new BigDecimal(Strings.repeat("9", 30) + "." + Strings.repeat("9", 9)).multiply(sign)); + fail("Missing expected exception"); + } catch (SpannerException e) { + assertThat(e.getErrorCode()).isEqualTo(ErrorCode.OUT_OF_RANGE); + } + try { + Value.numeric( + new BigDecimal("1" + Strings.repeat("0", 29) + "." + Strings.repeat("9", 9)) + .multiply(sign)); + fail("Missing expected exception"); + } catch (SpannerException e) { + assertThat(e.getErrorCode()).isEqualTo(ErrorCode.OUT_OF_RANGE); + } + + try { + Value.numeric( + new BigDecimal(Strings.repeat("9", 29) + "." + Strings.repeat("9", 10)).multiply(sign)); + fail("Missing expected exception"); + } catch (SpannerException e) { + assertThat(e.getErrorCode()).isEqualTo(ErrorCode.OUT_OF_RANGE); + } + try { + Value.numeric(new BigDecimal("1." + Strings.repeat("9", 10)).multiply(sign)); + fail("Missing expected exception"); + } catch (SpannerException e) { + assertThat(e.getErrorCode()).isEqualTo(ErrorCode.OUT_OF_RANGE); + } + } + } + @Test public void numericNull() { Value v = Value.numeric(null); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITQueryTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITQueryTest.java index 4bb788031b9..02b2dac2d8e 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITQueryTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITQueryTest.java @@ -16,7 +16,6 @@ package com.google.cloud.spanner.it; -import static com.google.cloud.spanner.Type.StructField; import static com.google.cloud.spanner.testing.EmulatorSpannerHelper.isUsingEmulator; import static com.google.common.truth.Truth.assertThat; import static java.util.Arrays.asList; @@ -39,10 +38,13 @@ import com.google.cloud.spanner.Struct; import com.google.cloud.spanner.TimestampBound; import com.google.cloud.spanner.Type; +import com.google.cloud.spanner.Type.StructField; import com.google.cloud.spanner.Value; +import com.google.cloud.spanner.testing.EmulatorSpannerHelper; import com.google.common.base.Joiner; import com.google.common.collect.Iterables; import com.google.spanner.v1.ResultSetStats; +import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -269,6 +271,34 @@ public void bindDateNull() { assertThat(row.isNull(0)).isTrue(); } + @Test + public void bindNumeric() { + assumeFalse("Emulator does not yet support NUMERIC", EmulatorSpannerHelper.isUsingEmulator()); + BigDecimal b = new BigDecimal("1.1"); + Struct row = execute(Statement.newBuilder("SELECT @v").bind("v").to(b), Type.numeric()); + assertThat(row.isNull(0)).isFalse(); + assertThat(row.getBigDecimal(0)).isEqualTo(b); + } + + @Test + public void bindNumericNull() { + assumeFalse("Emulator does not yet support NUMERIC", EmulatorSpannerHelper.isUsingEmulator()); + Struct row = + execute(Statement.newBuilder("SELECT @v").bind("v").to((BigDecimal) null), Type.numeric()); + assertThat(row.isNull(0)).isTrue(); + } + + @Test + public void bindNumeric_doesNotPreservePrecision() { + assumeFalse("Emulator does not yet support NUMERIC", EmulatorSpannerHelper.isUsingEmulator()); + BigDecimal b = new BigDecimal("1.10"); + Struct row = execute(Statement.newBuilder("SELECT @v").bind("v").to(b), Type.numeric()); + assertThat(row.isNull(0)).isFalse(); + // Cloud Spanner does not store precision, and will therefore return 1.10 as 1.1. + assertThat(row.getBigDecimal(0)).isNotEqualTo(b); + assertThat(row.getBigDecimal(0)).isEqualTo(b.stripTrailingZeros()); + } + @Test public void bindBoolArray() { Struct row = @@ -494,6 +524,57 @@ public void bindDateArrayNull() { assertThat(row.isNull(0)).isTrue(); } + @Test + public void bindNumericArray() { + assumeFalse("Emulator does not yet support NUMERIC", EmulatorSpannerHelper.isUsingEmulator()); + BigDecimal b1 = new BigDecimal("3.14"); + BigDecimal b2 = new BigDecimal("6.626"); + + Struct row = + execute( + Statement.newBuilder("SELECT @v").bind("v").toNumericArray(asList(b1, b2, null)), + Type.array(Type.numeric())); + assertThat(row.isNull(0)).isFalse(); + assertThat(row.getBigDecimalList(0)).containsExactly(b1, b2, null).inOrder(); + } + + @Test + public void bindNumericArrayEmpty() { + assumeFalse("Emulator does not yet support NUMERIC", EmulatorSpannerHelper.isUsingEmulator()); + Struct row = + execute( + Statement.newBuilder("SELECT @v").bind("v").toNumericArray(Arrays.asList()), + Type.array(Type.numeric())); + assertThat(row.isNull(0)).isFalse(); + assertThat(row.getBigDecimalList(0)).containsExactly(); + } + + @Test + public void bindNumericArrayNull() { + assumeFalse("Emulator does not yet support NUMERIC", EmulatorSpannerHelper.isUsingEmulator()); + Struct row = + execute( + Statement.newBuilder("SELECT @v").bind("v").toNumericArray(null), + Type.array(Type.numeric())); + assertThat(row.isNull(0)).isTrue(); + } + + @Test + public void bindNumericArray_doesNotPreservePrecision() { + assumeFalse("Emulator does not yet support NUMERIC", EmulatorSpannerHelper.isUsingEmulator()); + BigDecimal b1 = new BigDecimal("3.14"); + BigDecimal b2 = new BigDecimal("6.626070"); + + Struct row = + execute( + Statement.newBuilder("SELECT @v").bind("v").toNumericArray(asList(b1, b2, null)), + Type.array(Type.numeric())); + assertThat(row.isNull(0)).isFalse(); + assertThat(row.getBigDecimalList(0)) + .containsExactly(b1.stripTrailingZeros(), b2.stripTrailingZeros(), null) + .inOrder(); + } + @Test public void unsupportedSelectStructValue() { assumeFalse("The emulator accepts this query", isUsingEmulator()); From 51d07f0e17a1de36ccb219f6fac88c575dd0e99e Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Mon, 21 Sep 2020 07:38:41 +0200 Subject: [PATCH 02/19] chore(deps): update dependency com.google.cloud:google-cloud-spanner to v2.0.1 (#440) --- samples/install-without-bom/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/install-without-bom/pom.xml b/samples/install-without-bom/pom.xml index c478a9cfe56..283fc71b838 100644 --- a/samples/install-without-bom/pom.xml +++ b/samples/install-without-bom/pom.xml @@ -29,7 +29,7 @@ com.google.cloud google-cloud-spanner - 2.0.0 + 2.0.1 From 5c0f5e0326a55f79c72c0c3562896b620855a4e6 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Tue, 22 Sep 2020 11:59:47 +1000 Subject: [PATCH 03/19] chore: release 2.0.2-SNAPSHOT (#439) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- google-cloud-spanner-bom/pom.xml | 18 +++++++++--------- google-cloud-spanner/pom.xml | 4 ++-- .../pom.xml | 4 ++-- .../pom.xml | 4 ++-- grpc-google-cloud-spanner-v1/pom.xml | 4 ++-- pom.xml | 16 ++++++++-------- .../pom.xml | 4 ++-- .../pom.xml | 4 ++-- proto-google-cloud-spanner-v1/pom.xml | 4 ++-- samples/snapshot/pom.xml | 2 +- versions.txt | 14 +++++++------- 11 files changed, 39 insertions(+), 39 deletions(-) diff --git a/google-cloud-spanner-bom/pom.xml b/google-cloud-spanner-bom/pom.xml index eb6d87e0488..3c191c2902c 100644 --- a/google-cloud-spanner-bom/pom.xml +++ b/google-cloud-spanner-bom/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.google.cloud google-cloud-spanner-bom - 2.0.1 + 2.0.2-SNAPSHOT pom com.google.cloud @@ -64,43 +64,43 @@ com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 2.0.1 + 2.0.2-SNAPSHOT com.google.api.grpc grpc-google-cloud-spanner-v1 - 2.0.1 + 2.0.2-SNAPSHOT com.google.api.grpc proto-google-cloud-spanner-v1 - 2.0.1 + 2.0.2-SNAPSHOT com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 2.0.1 + 2.0.2-SNAPSHOT com.google.cloud google-cloud-spanner - 2.0.1 + 2.0.2-SNAPSHOT com.google.cloud google-cloud-spanner test-jar - 2.0.1 + 2.0.2-SNAPSHOT com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 2.0.1 + 2.0.2-SNAPSHOT com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 2.0.1 + 2.0.2-SNAPSHOT diff --git a/google-cloud-spanner/pom.xml b/google-cloud-spanner/pom.xml index a135d1ff4e8..eca5aefb0bf 100644 --- a/google-cloud-spanner/pom.xml +++ b/google-cloud-spanner/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.google.cloud google-cloud-spanner - 2.0.1 + 2.0.2-SNAPSHOT jar Google Cloud Spanner https://github.com/googleapis/java-spanner @@ -11,7 +11,7 @@ com.google.cloud google-cloud-spanner-parent - 2.0.1 + 2.0.2-SNAPSHOT google-cloud-spanner diff --git a/grpc-google-cloud-spanner-admin-database-v1/pom.xml b/grpc-google-cloud-spanner-admin-database-v1/pom.xml index 2d44f93769b..1d75aa339e1 100644 --- a/grpc-google-cloud-spanner-admin-database-v1/pom.xml +++ b/grpc-google-cloud-spanner-admin-database-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 2.0.1 + 2.0.2-SNAPSHOT grpc-google-cloud-spanner-admin-database-v1 GRPC library for grpc-google-cloud-spanner-admin-database-v1 com.google.cloud google-cloud-spanner-parent - 2.0.1 + 2.0.2-SNAPSHOT diff --git a/grpc-google-cloud-spanner-admin-instance-v1/pom.xml b/grpc-google-cloud-spanner-admin-instance-v1/pom.xml index 1467dd6efe3..9fc40770a43 100644 --- a/grpc-google-cloud-spanner-admin-instance-v1/pom.xml +++ b/grpc-google-cloud-spanner-admin-instance-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 2.0.1 + 2.0.2-SNAPSHOT grpc-google-cloud-spanner-admin-instance-v1 GRPC library for grpc-google-cloud-spanner-admin-instance-v1 com.google.cloud google-cloud-spanner-parent - 2.0.1 + 2.0.2-SNAPSHOT diff --git a/grpc-google-cloud-spanner-v1/pom.xml b/grpc-google-cloud-spanner-v1/pom.xml index 222d4b65481..616c73dd933 100644 --- a/grpc-google-cloud-spanner-v1/pom.xml +++ b/grpc-google-cloud-spanner-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-spanner-v1 - 2.0.1 + 2.0.2-SNAPSHOT grpc-google-cloud-spanner-v1 GRPC library for grpc-google-cloud-spanner-v1 com.google.cloud google-cloud-spanner-parent - 2.0.1 + 2.0.2-SNAPSHOT diff --git a/pom.xml b/pom.xml index 1a18a6388e8..d81c09cfc25 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.google.cloud google-cloud-spanner-parent pom - 2.0.1 + 2.0.2-SNAPSHOT Google Cloud Spanner Parent https://github.com/googleapis/java-spanner @@ -70,37 +70,37 @@ com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 2.0.1 + 2.0.2-SNAPSHOT com.google.api.grpc proto-google-cloud-spanner-v1 - 2.0.1 + 2.0.2-SNAPSHOT com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 2.0.1 + 2.0.2-SNAPSHOT com.google.api.grpc grpc-google-cloud-spanner-v1 - 2.0.1 + 2.0.2-SNAPSHOT com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 2.0.1 + 2.0.2-SNAPSHOT com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 2.0.1 + 2.0.2-SNAPSHOT com.google.cloud google-cloud-spanner - 2.0.1 + 2.0.2-SNAPSHOT diff --git a/proto-google-cloud-spanner-admin-database-v1/pom.xml b/proto-google-cloud-spanner-admin-database-v1/pom.xml index f096f9a5fdf..8ce39c38b35 100644 --- a/proto-google-cloud-spanner-admin-database-v1/pom.xml +++ b/proto-google-cloud-spanner-admin-database-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 2.0.1 + 2.0.2-SNAPSHOT proto-google-cloud-spanner-admin-database-v1 PROTO library for proto-google-cloud-spanner-admin-database-v1 com.google.cloud google-cloud-spanner-parent - 2.0.1 + 2.0.2-SNAPSHOT diff --git a/proto-google-cloud-spanner-admin-instance-v1/pom.xml b/proto-google-cloud-spanner-admin-instance-v1/pom.xml index 1687f79c928..f6e85dacbfd 100644 --- a/proto-google-cloud-spanner-admin-instance-v1/pom.xml +++ b/proto-google-cloud-spanner-admin-instance-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 2.0.1 + 2.0.2-SNAPSHOT proto-google-cloud-spanner-admin-instance-v1 PROTO library for proto-google-cloud-spanner-admin-instance-v1 com.google.cloud google-cloud-spanner-parent - 2.0.1 + 2.0.2-SNAPSHOT diff --git a/proto-google-cloud-spanner-v1/pom.xml b/proto-google-cloud-spanner-v1/pom.xml index 04eac082570..6f263f9b0de 100644 --- a/proto-google-cloud-spanner-v1/pom.xml +++ b/proto-google-cloud-spanner-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-spanner-v1 - 2.0.1 + 2.0.2-SNAPSHOT proto-google-cloud-spanner-v1 PROTO library for proto-google-cloud-spanner-v1 com.google.cloud google-cloud-spanner-parent - 2.0.1 + 2.0.2-SNAPSHOT diff --git a/samples/snapshot/pom.xml b/samples/snapshot/pom.xml index d085222e6ca..240e06cadfa 100644 --- a/samples/snapshot/pom.xml +++ b/samples/snapshot/pom.xml @@ -28,7 +28,7 @@ com.google.cloud google-cloud-spanner - 2.0.1 + 2.0.2-SNAPSHOT diff --git a/versions.txt b/versions.txt index 56bbc5754f4..3e90a37327f 100644 --- a/versions.txt +++ b/versions.txt @@ -1,10 +1,10 @@ # Format: # module:released-version:current-version -proto-google-cloud-spanner-admin-instance-v1:2.0.1:2.0.1 -proto-google-cloud-spanner-v1:2.0.1:2.0.1 -proto-google-cloud-spanner-admin-database-v1:2.0.1:2.0.1 -grpc-google-cloud-spanner-v1:2.0.1:2.0.1 -grpc-google-cloud-spanner-admin-instance-v1:2.0.1:2.0.1 -grpc-google-cloud-spanner-admin-database-v1:2.0.1:2.0.1 -google-cloud-spanner:2.0.1:2.0.1 \ No newline at end of file +proto-google-cloud-spanner-admin-instance-v1:2.0.1:2.0.2-SNAPSHOT +proto-google-cloud-spanner-v1:2.0.1:2.0.2-SNAPSHOT +proto-google-cloud-spanner-admin-database-v1:2.0.1:2.0.2-SNAPSHOT +grpc-google-cloud-spanner-v1:2.0.1:2.0.2-SNAPSHOT +grpc-google-cloud-spanner-admin-instance-v1:2.0.1:2.0.2-SNAPSHOT +grpc-google-cloud-spanner-admin-database-v1:2.0.1:2.0.2-SNAPSHOT +google-cloud-spanner:2.0.1:2.0.2-SNAPSHOT \ No newline at end of file From 73f97337f7fddaed538c0e262d8a481770e8ef3d Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Mon, 21 Sep 2020 20:14:57 -0700 Subject: [PATCH 04/19] chore: updates spanner dependency in README (#433) Updates spanner dependency version in README to the latest (2.0.1). --- README.md | 2 +- synth.metadata | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 79217260c17..40b9969a4bc 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ If you are using Maven without BOM, add this to your dependencies: com.google.cloud google-cloud-spanner - 1.60.0 + 2.0.1 ``` diff --git a/synth.metadata b/synth.metadata index cfc89d52e3b..cdd58d65a9b 100644 --- a/synth.metadata +++ b/synth.metadata @@ -4,7 +4,7 @@ "git": { "name": ".", "remote": "https://github.com/googleapis/java-spanner.git", - "sha": "b35304ede5c980c3c042b89247058cc5a4ab1488" + "sha": "51d07f0e17a1de36ccb219f6fac88c575dd0e99e" } }, { From 2d7c50957cdcbea7607723f73beb91dfbe9717c8 Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Tue, 22 Sep 2020 11:36:17 -0700 Subject: [PATCH 05/19] chore: regenerate common templates (#443) This PR was generated using Autosynth. :rainbow: Synth log will be available here: https://source.cloud.google.com/results/invocations/1659e5a3-ce7a-4440-8e7f-0dc13b0c12fa/targets - [ ] To automatically regenerate this PR, check this box. Source-Link: https://github.com/googleapis/synthtool/commit/80003a3de2d8a75f5b47cb2e77e018f7f0f776cc Source-Link: https://github.com/googleapis/synthtool/commit/538a68019eb4a36a0cdfa4021f324dd01b784395 --- .github/CODEOWNERS | 2 + .github/workflows/auto-release.yaml | 69 +++++++++++++++++++++++++++++ synth.metadata | 5 ++- 3 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/auto-release.yaml diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 6137bef2a25..30fdb7b9c8f 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -4,5 +4,7 @@ # For syntax help see: # https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners#codeowners-syntax +* @googleapis/yoshi-java + # The java-samples-reviewers team is the default owner for samples changes samples/**/*.java @googleapis/java-samples-reviewers diff --git a/.github/workflows/auto-release.yaml b/.github/workflows/auto-release.yaml new file mode 100644 index 00000000000..d26427e468a --- /dev/null +++ b/.github/workflows/auto-release.yaml @@ -0,0 +1,69 @@ +on: + pull_request: +name: auto-release +jobs: + approve: + runs-on: ubuntu-latest + steps: + - uses: actions/github-script@v3.0.0 + with: + github-token: ${{secrets.GITHUB_TOKEN}} + debug: true + script: | + // only approve PRs from release-please[bot] + if (context.payload.pull_request.user.login !== "release-please[bot]") { + return; + } + + // only approve PRs like "chore: release " + if ( !context.payload.pull_request.title.startsWith("chore: release") ) { + return; + } + + // trigger auto-release when + // 1) it is a SNAPSHOT release (auto-generated post regular release) + // 2) there are dependency updates only + // 3) there are no open dependency update PRs in this repo (to avoid multiple releases) + if ( + context.payload.pull_request.body.includes("Fix") || + context.payload.pull_request.body.includes("Build") || + context.payload.pull_request.body.includes("Documentation") || + context.payload.pull_request.body.includes("BREAKING CHANGES") || + context.payload.pull_request.body.includes("Features") + ) { + console.log( "Not auto-releasing since it is not a dependency-update-only release." ); + return; + } + + const promise = github.pulls.list.endpoint({ + owner: context.repo.owner, + repo: context.repo.repo, + state: 'open' + }); + const open_pulls = await github.paginate(promise) + + if ( open_pulls.length > 1 && !context.payload.pull_request.title.includes("SNAPSHOT") ) { + for ( const pull of open_pulls ) { + if ( pull.title.startsWith("deps: update dependency") ) { + console.log( "Not auto-releasing yet since there are dependency update PRs open in this repo." ); + return; + } + } + } + + // approve release PR + await github.pulls.createReview({ + owner: context.repo.owner, + repo: context.repo.repo, + body: 'Rubber stamped release!', + pull_number: context.payload.pull_request.number, + event: 'APPROVE' + }); + + // attach kokoro:force-run and automerge labels + await github.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.pull_request.number, + labels: ['kokoro:force-run', 'automerge'] + }); \ No newline at end of file diff --git a/synth.metadata b/synth.metadata index cdd58d65a9b..f30ceded1bc 100644 --- a/synth.metadata +++ b/synth.metadata @@ -4,7 +4,7 @@ "git": { "name": ".", "remote": "https://github.com/googleapis/java-spanner.git", - "sha": "51d07f0e17a1de36ccb219f6fac88c575dd0e99e" + "sha": "73f97337f7fddaed538c0e262d8a481770e8ef3d" } }, { @@ -19,7 +19,7 @@ "git": { "name": "synthtool", "remote": "https://github.com/googleapis/synthtool.git", - "sha": "019c7168faa0e56619f792693a8acdb30d6de19b" + "sha": "80003a3de2d8a75f5b47cb2e77e018f7f0f776cc" } } ], @@ -60,6 +60,7 @@ ".github/PULL_REQUEST_TEMPLATE.md", ".github/release-please.yml", ".github/trusted-contribution.yml", + ".github/workflows/auto-release.yaml", ".github/workflows/ci.yaml", ".github/workflows/samples.yaml", ".kokoro/build.bat", From e05ee0eaa16984393b60fc47f94412e560c36ff1 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Wed, 23 Sep 2020 22:52:03 +0200 Subject: [PATCH 06/19] deps: update dependency com.google.cloud:google-cloud-shared-dependencies to v0.10.0 (#453) This PR contains the following updates: | Package | Update | Change | |---|---|---| | [com.google.cloud:google-cloud-shared-dependencies](https://togithub.com/googleapis/java-shared-dependencies) | minor | `0.9.0` -> `0.10.0` | --- ### Release Notes

googleapis/java-shared-dependencies ### [`v0.10.0`](https://togithub.com/googleapis/java-shared-dependencies/blob/master/CHANGELOG.md#​0100-httpswwwgithubcomgoogleapisjava-shared-dependenciescompare091v0100-2020-09-23) [Compare Source](https://togithub.com/googleapis/java-shared-dependencies/compare/v0.9.1...v0.10.0) ##### Features - manage error-prone version ([#​147](https://www.github.com/googleapis/java-shared-dependencies/issues/147)) ([0fb3108](https://www.github.com/googleapis/java-shared-dependencies/commit/0fb3108c96abcdef83b5051e842530e6c9934c37)) ##### Dependencies - update google.core.version to v1.93.9 ([#​148](https://www.github.com/googleapis/java-shared-dependencies/issues/148)) ([b2a680e](https://www.github.com/googleapis/java-shared-dependencies/commit/b2a680ec9297136dceb622463672cc554359ba5b)) ##### [0.9.1](https://www.github.com/googleapis/java-shared-dependencies/compare/0.9.0...v0.9.1) (2020-09-23) ##### Dependencies - update dependency io.grpc:grpc-bom to v1.32.1 ([#​133](https://www.github.com/googleapis/java-shared-dependencies/issues/133)) ([cde0463](https://www.github.com/googleapis/java-shared-dependencies/commit/cde0463dd15c2a510085a3d5e3ac7b418c2fc3d4)) - update iam.version to v1.0.1 ([#​136](https://www.github.com/googleapis/java-shared-dependencies/issues/136)) ([162e2bd](https://www.github.com/googleapis/java-shared-dependencies/commit/162e2bda35fc3427ce571c6747aae4c9eb5866f6)) ### [`v0.9.1`](https://togithub.com/googleapis/java-shared-dependencies/blob/master/CHANGELOG.md#​091-httpswwwgithubcomgoogleapisjava-shared-dependenciescompare090v091-2020-09-23) [Compare Source](https://togithub.com/googleapis/java-shared-dependencies/compare/v0.9.0...v0.9.1)
--- ### Renovate configuration :date: **Schedule**: At any time (no schedule defined). :vertical_traffic_light: **Automerge**: Disabled by config. Please merge this manually once you are satisfied. :recycle: **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. :no_bell: **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [WhiteSource Renovate](https://renovate.whitesourcesoftware.com). View repository job log [here](https://app.renovatebot.com/dashboard#github/googleapis/java-spanner). --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d81c09cfc25..2d8e95c650b 100644 --- a/pom.xml +++ b/pom.xml @@ -106,7 +106,7 @@ com.google.cloud google-cloud-shared-dependencies - 0.9.0 + 0.10.0 pom import From 7cb81081fdca986cc0a80e172a3f322a48157983 Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Wed, 23 Sep 2020 15:46:04 -0700 Subject: [PATCH 07/19] build(java): use yoshi-approver token for auto-approve (#454) This PR was generated using Autosynth. :rainbow: Synth log will be available here: https://source.cloud.google.com/results/invocations/24b2f5f7-a563-4efc-b279-c0403f4fd854/targets - [ ] To automatically regenerate this PR, check this box. Source-Link: https://github.com/googleapis/synthtool/commit/916c10e8581804df2b48a0f0457d848f3faa582e --- .github/workflows/auto-release.yaml | 4 ++-- synth.metadata | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/auto-release.yaml b/.github/workflows/auto-release.yaml index d26427e468a..c8494910553 100644 --- a/.github/workflows/auto-release.yaml +++ b/.github/workflows/auto-release.yaml @@ -7,7 +7,7 @@ jobs: steps: - uses: actions/github-script@v3.0.0 with: - github-token: ${{secrets.GITHUB_TOKEN}} + github-token: ${{secrets.YOSHI_APPROVER_TOKEN}} debug: true script: | // only approve PRs from release-please[bot] @@ -66,4 +66,4 @@ jobs: repo: context.repo.repo, issue_number: context.payload.pull_request.number, labels: ['kokoro:force-run', 'automerge'] - }); \ No newline at end of file + }); diff --git a/synth.metadata b/synth.metadata index f30ceded1bc..012b02a720e 100644 --- a/synth.metadata +++ b/synth.metadata @@ -4,7 +4,7 @@ "git": { "name": ".", "remote": "https://github.com/googleapis/java-spanner.git", - "sha": "73f97337f7fddaed538c0e262d8a481770e8ef3d" + "sha": "e05ee0eaa16984393b60fc47f94412e560c36ff1" } }, { @@ -19,7 +19,7 @@ "git": { "name": "synthtool", "remote": "https://github.com/googleapis/synthtool.git", - "sha": "80003a3de2d8a75f5b47cb2e77e018f7f0f776cc" + "sha": "916c10e8581804df2b48a0f0457d848f3faa582e" } } ], From e620a1572979efbcb25ef8adab3b60144e19f623 Mon Sep 17 00:00:00 2001 From: Jeff Ching Date: Thu, 24 Sep 2020 14:00:14 -0700 Subject: [PATCH 08/19] chore: add repo settings configuration (#455) --- .github/sync-repo-settings.yaml | 49 +++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 .github/sync-repo-settings.yaml diff --git a/.github/sync-repo-settings.yaml b/.github/sync-repo-settings.yaml new file mode 100644 index 00000000000..6bddd18eac9 --- /dev/null +++ b/.github/sync-repo-settings.yaml @@ -0,0 +1,49 @@ + +# Whether or not rebase-merging is enabled on this repository. +# Defaults to `true` +rebaseMergeAllowed: false + +# Whether or not squash-merging is enabled on this repository. +# Defaults to `true` +squashMergeAllowed: true + +# Whether or not PRs are merged with a merge commit on this repository. +# Defaults to `false` +mergeCommitAllowed: false + +# Rules for master branch protection +branchProtectionRules: +# Identifies the protection rule pattern. Name of the branch to be protected. +# Defaults to `master` +- pattern: master + # Can admins overwrite branch protection. + # Defaults to `true` + isAdminEnforced: true + # Number of approving reviews required to update matching branches. + # Defaults to `1` + requiredApprovingReviewCount: 1 + # Are reviews from code owners required to update matching branches. + # Defaults to `false` + requiresCodeOwnerReviews: true + # Require up to date branches + requiresStrictStatusChecks: false + # List of required status check contexts that must pass for commits to be accepted to matching branches. + requiredStatusCheckContexts: + - "dependencies (8)" + - "dependencies (11)" + - "linkage-monitor" + - "lint" + - "clirr" + - "units (7)" + - "units (8)" + - "units (11)" + - "Kokoro - Test: Integration" + - "cla/google" +# List of explicit permissions to add (additive only) +permissionRules: +- team: yoshi-admins + permission: admin +- team: yoshi-java-admins + permission: admin +- team: yoshi-java + permission: push \ No newline at end of file From 28103fb2d6e293d20399ecdfd680be67d9d62a1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Tue, 29 Sep 2020 14:15:35 +0200 Subject: [PATCH 09/19] fix: use credentials key in pool (#430) * fix: use credentials key in pool * fix: remove unused test class * test: increase test coverage --- .../spanner/connection/ConnectionOptions.java | 17 +++++-- .../cloud/spanner/connection/SpannerPool.java | 46 +++++++++++++++---- .../spanner/ResumableStreamIteratorTest.java | 32 +++++++++++++ .../spanner/connection/SpannerPoolTest.java | 27 +++++++---- 4 files changed, 102 insertions(+), 20 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java index 0b1bc8d21bd..379459884c7 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java @@ -384,6 +384,7 @@ public static Builder newBuilder() { private final String uri; private final String credentialsUrl; private final String oauthToken; + private final Credentials fixedCredentials; private final boolean usePlainText; private final String host; @@ -413,6 +414,7 @@ private ConnectionOptions(Builder builder) { builder.credentialsUrl != null ? builder.credentialsUrl : parseCredentials(builder.uri); this.oauthToken = builder.oauthToken != null ? builder.oauthToken : parseOAuthToken(builder.uri); + this.fixedCredentials = builder.credentials; // Check that not both credentials and an OAuth token have been specified. Preconditions.checkArgument( (builder.credentials == null && this.credentialsUrl == null) || this.oauthToken == null, @@ -441,11 +443,10 @@ private ConnectionOptions(Builder builder) { this.credentials = NoCredentials.getInstance(); } else if (this.oauthToken != null) { this.credentials = new GoogleCredentials(new AccessToken(oauthToken, null)); + } else if (this.fixedCredentials != null) { + this.credentials = fixedCredentials; } else { - this.credentials = - builder.credentials == null - ? getCredentialsService().createCredentials(this.credentialsUrl) - : builder.credentials; + this.credentials = getCredentialsService().createCredentials(this.credentialsUrl); } String numChannelsValue = parseNumChannels(builder.uri); if (numChannelsValue != null) { @@ -593,6 +594,14 @@ public String getCredentialsUrl() { return credentialsUrl; } + String getOAuthToken() { + return this.oauthToken; + } + + Credentials getFixedCredentials() { + return this.fixedCredentials; + } + /** The {@link SessionPoolOptions} of this {@link ConnectionOptions}. */ public SessionPoolOptions getSessionPoolOptions() { return sessionPoolOptions; diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/SpannerPool.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/SpannerPool.java index 7116bc17f35..ecf13cd399f 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/SpannerPool.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/SpannerPool.java @@ -17,7 +17,6 @@ package com.google.cloud.spanner.connection; import com.google.api.core.ApiFunction; -import com.google.auth.Credentials; import com.google.cloud.NoCredentials; import com.google.cloud.spanner.ErrorCode; import com.google.cloud.spanner.SessionPoolOptions; @@ -28,8 +27,11 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.MoreObjects; import com.google.common.base.Preconditions; +import com.google.common.base.Predicates; +import com.google.common.collect.Iterables; import io.grpc.ManagedChannelBuilder; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -108,10 +110,38 @@ public void run() { } } + static class CredentialsKey { + static final Object DEFAULT_CREDENTIALS_KEY = new Object(); + final Object key; + + static CredentialsKey create(ConnectionOptions options) { + return new CredentialsKey( + Iterables.find( + Arrays.asList( + options.getOAuthToken(), + options.getFixedCredentials(), + options.getCredentialsUrl(), + DEFAULT_CREDENTIALS_KEY), + Predicates.notNull())); + } + + private CredentialsKey(Object key) { + this.key = Preconditions.checkNotNull(key); + } + + public int hashCode() { + return key.hashCode(); + } + + public boolean equals(Object o) { + return (o instanceof CredentialsKey && Objects.equals(((CredentialsKey) o).key, this.key)); + } + } + static class SpannerPoolKey { private final String host; private final String projectId; - private final Credentials credentials; + private final CredentialsKey credentialsKey; private final SessionPoolOptions sessionPoolOptions; private final Integer numChannels; private final boolean usePlainText; @@ -124,7 +154,7 @@ private static SpannerPoolKey of(ConnectionOptions options) { private SpannerPoolKey(ConnectionOptions options) { this.host = options.getHost(); this.projectId = options.getProjectId(); - this.credentials = options.getCredentials(); + this.credentialsKey = CredentialsKey.create(options); this.sessionPoolOptions = options.getSessionPoolOptions(); this.numChannels = options.getNumChannels(); this.usePlainText = options.isUsePlainText(); @@ -139,7 +169,7 @@ public boolean equals(Object o) { SpannerPoolKey other = (SpannerPoolKey) o; return Objects.equals(this.host, other.host) && Objects.equals(this.projectId, other.projectId) - && Objects.equals(this.credentials, other.credentials) + && Objects.equals(this.credentialsKey, other.credentialsKey) && Objects.equals(this.sessionPoolOptions, other.sessionPoolOptions) && Objects.equals(this.numChannels, other.numChannels) && Objects.equals(this.usePlainText, other.usePlainText) @@ -151,7 +181,7 @@ public int hashCode() { return Objects.hash( this.host, this.projectId, - this.credentials, + this.credentialsKey, this.sessionPoolOptions, this.numChannels, this.usePlainText, @@ -240,7 +270,7 @@ Spanner getSpanner(ConnectionOptions options, ConnectionImpl connection) { if (spanners.get(key) != null) { spanner = spanners.get(key); } else { - spanner = createSpanner(key); + spanner = createSpanner(key, options); spanners.put(key, spanner); } List registeredConnectionsForSpanner = connections.get(key); @@ -279,13 +309,13 @@ public Thread newThread(Runnable r) { @SuppressWarnings("rawtypes") @VisibleForTesting - Spanner createSpanner(SpannerPoolKey key) { + Spanner createSpanner(SpannerPoolKey key, ConnectionOptions options) { SpannerOptions.Builder builder = SpannerOptions.newBuilder(); builder .setClientLibToken(MoreObjects.firstNonNull(key.userAgent, CONNECTION_API_CLIENT_LIB_TOKEN)) .setHost(key.host) .setProjectId(key.projectId) - .setCredentials(key.credentials); + .setCredentials(options.getCredentials()); builder.setSessionPoolOption(key.sessionPoolOptions); if (key.numChannels != null) { builder.setNumChannels(key.numChannels); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ResumableStreamIteratorTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ResumableStreamIteratorTest.java index 6c387f0d48b..ef744d31a10 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ResumableStreamIteratorTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ResumableStreamIteratorTest.java @@ -21,6 +21,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import com.google.api.client.util.BackOff; import com.google.common.collect.AbstractIterator; import com.google.common.collect.Lists; import com.google.protobuf.ByteString; @@ -29,10 +30,12 @@ import com.google.rpc.RetryInfo; import com.google.spanner.v1.PartialResultSet; import io.grpc.Metadata; +import io.grpc.Status; import io.grpc.StatusRuntimeException; import io.grpc.protobuf.ProtoUtils; import io.opencensus.trace.EndSpanOptions; import io.opencensus.trace.Span; +import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; @@ -79,6 +82,11 @@ static class RetryableException extends SpannerException { // OK to instantiate SpannerException directly for this unit test. super(DoNotConstructDirectly.ALLOWED, code, true, message, statusWithRetryInfo(code)); } + + RetryableException(ErrorCode code, @Nullable String message, StatusRuntimeException cause) { + // OK to instantiate SpannerException directly for this unit test. + super(DoNotConstructDirectly.ALLOWED, code, true, message, cause); + } } static class NonRetryableException extends SpannerException { @@ -220,6 +228,30 @@ public void restartWithHoldBackMidStream() { .inOrder(); } + @Test + public void retryableErrorWithoutRetryInfo() throws IOException { + BackOff backOff = mock(BackOff.class); + Mockito.when(backOff.nextBackOffMillis()).thenReturn(1L); + Whitebox.setInternalState(this.resumableStreamIterator, "backOff", backOff); + + ResultSetStream s1 = Mockito.mock(ResultSetStream.class); + Mockito.when(starter.startStream(null)).thenReturn(new ResultSetIterator(s1)); + Mockito.when(s1.next()) + .thenReturn(resultSet(ByteString.copyFromUtf8("r1"), "a")) + .thenThrow( + new RetryableException( + ErrorCode.UNAVAILABLE, "failed by test", Status.UNAVAILABLE.asRuntimeException())); + + ResultSetStream s2 = Mockito.mock(ResultSetStream.class); + Mockito.when(starter.startStream(ByteString.copyFromUtf8("r1"))) + .thenReturn(new ResultSetIterator(s2)); + Mockito.when(s2.next()) + .thenReturn(resultSet(ByteString.copyFromUtf8("r2"), "b")) + .thenReturn(null); + assertThat(consume(resumableStreamIterator)).containsExactly("a", "b").inOrder(); + verify(backOff).nextBackOffMillis(); + } + @Test public void nonRetryableError() { ResultSetStream s1 = Mockito.mock(ResultSetStream.class); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SpannerPoolTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SpannerPoolTest.java index c0145203cec..3c0e9cf160e 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SpannerPoolTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SpannerPoolTest.java @@ -26,7 +26,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import com.google.auth.oauth2.GoogleCredentials; import com.google.cloud.NoCredentials; import com.google.cloud.spanner.ErrorCode; import com.google.cloud.spanner.SessionPoolOptions; @@ -34,6 +33,7 @@ import com.google.cloud.spanner.SpannerException; import com.google.cloud.spanner.connection.ConnectionImpl.LeakedConnectionException; import com.google.cloud.spanner.connection.SpannerPool.CheckAndCloseSpannersMode; +import com.google.cloud.spanner.connection.SpannerPool.SpannerPoolKey; import java.io.ByteArrayOutputStream; import java.io.OutputStream; import java.util.logging.Handler; @@ -51,13 +51,16 @@ public class SpannerPoolTest { private ConnectionImpl connection1 = mock(ConnectionImpl.class); private ConnectionImpl connection2 = mock(ConnectionImpl.class); private ConnectionImpl connection3 = mock(ConnectionImpl.class); - private GoogleCredentials credentials1 = mock(GoogleCredentials.class); - private GoogleCredentials credentials2 = mock(GoogleCredentials.class); + private String credentials1 = "credentials1"; + private String credentials2 = "credentials2"; private ConnectionOptions options1 = mock(ConnectionOptions.class); private ConnectionOptions options2 = mock(ConnectionOptions.class); private ConnectionOptions options3 = mock(ConnectionOptions.class); private ConnectionOptions options4 = mock(ConnectionOptions.class); + private ConnectionOptions options5 = mock(ConnectionOptions.class); + private ConnectionOptions options6 = mock(ConnectionOptions.class); + private SpannerPool createSubjectAndMocks() { return createSubjectAndMocks(0L); } @@ -66,21 +69,25 @@ private SpannerPool createSubjectAndMocks(long closeSpannerAfterMillisecondsUnus SpannerPool pool = new SpannerPool(closeSpannerAfterMillisecondsUnused) { @Override - Spanner createSpanner(SpannerPoolKey key) { + Spanner createSpanner(SpannerPoolKey key, ConnectionOptions options) { return mock(Spanner.class); } }; - when(options1.getCredentials()).thenReturn(credentials1); + when(options1.getCredentialsUrl()).thenReturn(credentials1); when(options1.getProjectId()).thenReturn("test-project-1"); - when(options2.getCredentials()).thenReturn(credentials2); + when(options2.getCredentialsUrl()).thenReturn(credentials2); when(options2.getProjectId()).thenReturn("test-project-1"); - when(options3.getCredentials()).thenReturn(credentials1); + when(options3.getCredentialsUrl()).thenReturn(credentials1); when(options3.getProjectId()).thenReturn("test-project-2"); - when(options4.getCredentials()).thenReturn(credentials2); + when(options4.getCredentialsUrl()).thenReturn(credentials2); when(options4.getProjectId()).thenReturn("test-project-2"); + // ConnectionOptions with no specific credentials. + when(options5.getProjectId()).thenReturn("test-project-3"); + when(options6.getProjectId()).thenReturn("test-project-3"); + return pool; } @@ -108,6 +115,10 @@ public void testGetSpanner() { spanner1 = pool.getSpanner(options4, connection1); spanner2 = pool.getSpanner(options4, connection2); assertThat(spanner1, is(equalTo(spanner2))); + // Options 5 and 6 both use default credentials. + spanner1 = pool.getSpanner(options5, connection1); + spanner2 = pool.getSpanner(options6, connection2); + assertThat(spanner1, is(equalTo(spanner2))); // assert not equal spanner1 = pool.getSpanner(options1, connection1); From f037f2d28096cd173ba338a966fd16babe8c697e Mon Sep 17 00:00:00 2001 From: Thiago Nunes Date: Wed, 30 Sep 2020 13:24:25 +1000 Subject: [PATCH 10/19] fix: skip failing backup tests for now (#463) Until b/169431286 is fixed. --- .../java/com/google/cloud/spanner/it/ITDatabaseAdminTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITDatabaseAdminTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITDatabaseAdminTest.java index 167ab97ce4f..a683b05ab67 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITDatabaseAdminTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITDatabaseAdminTest.java @@ -63,6 +63,7 @@ import org.junit.After; import org.junit.Before; import org.junit.ClassRule; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -263,6 +264,7 @@ public void onClose(Status status, Metadata metadata) { } } + @Ignore("Skipping until list backup operations bug is fixed: b/169431286") @Test public void testRetryNonIdempotentRpcsReturningLongRunningOperations() throws Exception { assumeFalse( From c13995faa228e98c9c7bf657a1252b853d24a896 Mon Sep 17 00:00:00 2001 From: Thiago Nunes Date: Wed, 30 Sep 2020 16:25:26 +1000 Subject: [PATCH 11/19] chore: adds api-spanner-java group as codeowners (#462) * chore: adds api-spanner-java group as codeowners * chore: adds api-spanner-java into repo metadata --- .github/CODEOWNERS | 2 +- .repo-metadata.json | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 30fdb7b9c8f..2e8e575cf78 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -4,7 +4,7 @@ # For syntax help see: # https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners#codeowners-syntax -* @googleapis/yoshi-java +* @googleapis/yoshi-java @googleapis/api-spanner-java # The java-samples-reviewers team is the default owner for samples changes samples/**/*.java @googleapis/java-samples-reviewers diff --git a/.repo-metadata.json b/.repo-metadata.json index c0b5c5b3963..ea1bd1f3780 100644 --- a/.repo-metadata.json +++ b/.repo-metadata.json @@ -12,5 +12,6 @@ "distribution_name": "com.google.cloud:google-cloud-spanner", "api_id": "spanner.googleapis.com", "transport": "grpc", - "requires_billing": true -} \ No newline at end of file + "requires_billing": true, + "codeowner_team": "@googleapis/api-spanner-java" +} From 2c432d96055e237f4365e6b133cbfdf91f9c93fb Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Wed, 30 Sep 2020 21:05:36 -0700 Subject: [PATCH 12/19] chore(ci): skip autorelease workflow on non-release PRs (#459) Source-Author: Stephanie Wang Source-Date: Thu Sep 24 16:57:32 2020 -0400 Source-Repo: googleapis/synthtool Source-Sha: 95dbe1bee3c7f7e52ddb24a54c37080620e0d1a2 Source-Link: https://github.com/googleapis/synthtool/commit/95dbe1bee3c7f7e52ddb24a54c37080620e0d1a2 Co-authored-by: Thiago Nunes --- .github/workflows/auto-release.yaml | 1 + synth.metadata | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/auto-release.yaml b/.github/workflows/auto-release.yaml index c8494910553..3ce51eeea78 100644 --- a/.github/workflows/auto-release.yaml +++ b/.github/workflows/auto-release.yaml @@ -4,6 +4,7 @@ name: auto-release jobs: approve: runs-on: ubuntu-latest + if: contains(github.head_ref, 'release-v') steps: - uses: actions/github-script@v3.0.0 with: diff --git a/synth.metadata b/synth.metadata index 012b02a720e..df6ac52a3a4 100644 --- a/synth.metadata +++ b/synth.metadata @@ -4,7 +4,7 @@ "git": { "name": ".", "remote": "https://github.com/googleapis/java-spanner.git", - "sha": "e05ee0eaa16984393b60fc47f94412e560c36ff1" + "sha": "e620a1572979efbcb25ef8adab3b60144e19f623" } }, { @@ -19,7 +19,7 @@ "git": { "name": "synthtool", "remote": "https://github.com/googleapis/synthtool.git", - "sha": "916c10e8581804df2b48a0f0457d848f3faa582e" + "sha": "95dbe1bee3c7f7e52ddb24a54c37080620e0d1a2" } } ], From ec56a783f68b827b067072448a9fc24240b22d4d Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Thu, 1 Oct 2020 07:11:47 +0200 Subject: [PATCH 13/19] chore(deps): update dependency com.google.cloud:libraries-bom to v11 (#457) --- samples/snippets/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/snippets/pom.xml b/samples/snippets/pom.xml index 06c9d0fa37f..449df3271e6 100644 --- a/samples/snippets/pom.xml +++ b/samples/snippets/pom.xml @@ -30,7 +30,7 @@ com.google.cloud libraries-bom - 10.1.0 + 11.1.0 pom import From 81b07e31a6a63a795d904094a72a6b51e593c314 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Thu, 1 Oct 2020 07:12:14 +0200 Subject: [PATCH 14/19] chore(deps): update dependency com.google.cloud.samples:shared-configuration to v1.0.20 (#458) --- samples/install-without-bom/pom.xml | 2 +- samples/pom.xml | 2 +- samples/snapshot/pom.xml | 2 +- samples/snippets/pom.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/samples/install-without-bom/pom.xml b/samples/install-without-bom/pom.xml index 283fc71b838..79626289570 100644 --- a/samples/install-without-bom/pom.xml +++ b/samples/install-without-bom/pom.xml @@ -14,7 +14,7 @@ com.google.cloud.samples shared-configuration - 1.0.18 + 1.0.20 diff --git a/samples/pom.xml b/samples/pom.xml index cee7fc12505..21a9eb1c126 100644 --- a/samples/pom.xml +++ b/samples/pom.xml @@ -18,7 +18,7 @@ com.google.cloud.samples shared-configuration - 1.0.18 + 1.0.20 diff --git a/samples/snapshot/pom.xml b/samples/snapshot/pom.xml index 240e06cadfa..2dfe0f3c9fc 100644 --- a/samples/snapshot/pom.xml +++ b/samples/snapshot/pom.xml @@ -14,7 +14,7 @@ com.google.cloud.samples shared-configuration - 1.0.18 + 1.0.20 diff --git a/samples/snippets/pom.xml b/samples/snippets/pom.xml index 449df3271e6..5650c1f57ba 100644 --- a/samples/snippets/pom.xml +++ b/samples/snippets/pom.xml @@ -14,7 +14,7 @@ com.google.cloud.samples shared-configuration - 1.0.18 + 1.0.20 From ea42f4e66d5b3896288da64997f193bb804b0a1c Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Thu, 1 Oct 2020 10:49:38 -0700 Subject: [PATCH 15/19] chore: regenerate common templates (#488) * changes without context autosynth cannot find the source of changes triggered by earlier changes in this repository, or by version upgrades to tools such as linters. * chore(ci): verify autorelease release PR content has changes Source-Author: Stephanie Wang Source-Date: Thu Sep 24 18:06:14 2020 -0400 Source-Repo: googleapis/synthtool Source-Sha: da29da32b3a988457b49ae290112b74f14b713cc Source-Link: https://github.com/googleapis/synthtool/commit/da29da32b3a988457b49ae290112b74f14b713cc * chore(java): use separate autosynth job for README Split java README generation into a separate, per-repo continuous job running from Kokoro. We now generate a new job that runs on commits to the primary branch that strictly manages the README.md. This should prevent us from seeing the contextless autosynth PRs which are caused by non-proto/template upstream changes. Source-Author: Jeff Ching Source-Date: Tue Sep 29 15:48:03 2020 -0700 Source-Repo: googleapis/synthtool Source-Sha: e6168630be3e31eede633ba2c6f1cd64248dec1c Source-Link: https://github.com/googleapis/synthtool/commit/e6168630be3e31eede633ba2c6f1cd64248dec1c * build: rename samples lint workflow to checkstyle to disambiguate branch protection with unit lint Source-Author: BenWhitehead Source-Date: Wed Sep 30 15:14:05 2020 -0400 Source-Repo: googleapis/synthtool Source-Sha: 8a7a3021fe97aa0a3641db642fe2b767f1c8110f Source-Link: https://github.com/googleapis/synthtool/commit/8a7a3021fe97aa0a3641db642fe2b767f1c8110f * build(java): readme.sh should be executable Source-Author: Jeff Ching Source-Date: Wed Sep 30 13:20:04 2020 -0700 Source-Repo: googleapis/synthtool Source-Sha: 0762e8ee2ec21cdfc4d82020b985a104feb0453b Source-Link: https://github.com/googleapis/synthtool/commit/0762e8ee2ec21cdfc4d82020b985a104feb0453b --- .github/CODEOWNERS | 2 ++ .github/readme/synth.py | 19 ++++++++++ .github/workflows/auto-release.yaml | 18 ++++++++++ .github/workflows/samples.yaml | 2 +- .kokoro/continuous/readme.cfg | 55 +++++++++++++++++++++++++++++ .kokoro/readme.sh | 36 +++++++++++++++++++ synth.metadata | 8 +++-- 7 files changed, 136 insertions(+), 4 deletions(-) create mode 100644 .github/readme/synth.py create mode 100644 .kokoro/continuous/readme.cfg create mode 100755 .kokoro/readme.sh diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 2e8e575cf78..da6403b346e 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -4,7 +4,9 @@ # For syntax help see: # https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners#codeowners-syntax +# The @googleapis/api-spanner-java is the default owner for changes in this repo * @googleapis/yoshi-java @googleapis/api-spanner-java +**/*.java @googleapis/api-spanner-java # The java-samples-reviewers team is the default owner for samples changes samples/**/*.java @googleapis/java-samples-reviewers diff --git a/.github/readme/synth.py b/.github/readme/synth.py new file mode 100644 index 00000000000..7b48cc28d36 --- /dev/null +++ b/.github/readme/synth.py @@ -0,0 +1,19 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""This script is used to synthesize generated the README for this library.""" + +from synthtool.languages import java + +java.custom_templates(["java_library/README.md"]) diff --git a/.github/workflows/auto-release.yaml b/.github/workflows/auto-release.yaml index 3ce51eeea78..bc1554aecba 100644 --- a/.github/workflows/auto-release.yaml +++ b/.github/workflows/auto-release.yaml @@ -21,6 +21,24 @@ jobs: return; } + // only approve PRs with pom.xml and versions.txt changes + const filesPromise = github.pulls.listFiles.endpoint({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.payload.pull_request.number, + }); + const changed_files = await github.paginate(filesPromise) + + if ( changed_files.length < 1 ) { + console.log( "Not proceeding since PR is empty!" ) + return; + } + + if ( !changed_files.some(v => v.filename.includes("pom")) || !changed_files.some(v => v.filename.includes("versions.txt")) ) { + console.log( "PR file changes do not have pom.xml or versions.txt -- something is wrong. PTAL!" ) + return; + } + // trigger auto-release when // 1) it is a SNAPSHOT release (auto-generated post regular release) // 2) there are dependency updates only diff --git a/.github/workflows/samples.yaml b/.github/workflows/samples.yaml index a1d50073069..c46230a78c3 100644 --- a/.github/workflows/samples.yaml +++ b/.github/workflows/samples.yaml @@ -2,7 +2,7 @@ on: pull_request: name: samples jobs: - lint: + checkstyle: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 diff --git a/.kokoro/continuous/readme.cfg b/.kokoro/continuous/readme.cfg new file mode 100644 index 00000000000..acd7dd9717e --- /dev/null +++ b/.kokoro/continuous/readme.cfg @@ -0,0 +1,55 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Format: //devtools/kokoro/config/proto/build.proto + +env_vars: { + key: "TRAMPOLINE_IMAGE" + value: "gcr.io/cloud-devrel-kokoro-resources/python-multi" +} + +env_vars: { + key: "TRAMPOLINE_BUILD_FILE" + value: "github/java-spanner/.kokoro/readme.sh" +} + +# Build logs will be here +action { + define_artifacts { + regex: "**/*sponge_log.xml" + regex: "**/*sponge_log.log" + } +} + +# The github token is stored here. +before_action { + fetch_keystore { + keystore_resource { + keystore_config_id: 73713 + keyname: "yoshi-automation-github-key" + # TODO(theacodes): remove this after secrets have globally propagated + backend_type: FASTCONFIGPUSH + } + } +} + +# Common env vars for all repositories and builds. +env_vars: { + key: "GITHUB_USER" + value: "yoshi-automation" +} +env_vars: { + key: "GITHUB_EMAIL" + value: "yoshi-automation@google.com" +} diff --git a/.kokoro/readme.sh b/.kokoro/readme.sh new file mode 100755 index 00000000000..9b726a988b0 --- /dev/null +++ b/.kokoro/readme.sh @@ -0,0 +1,36 @@ +#!/bin/bash +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -eo pipefail + +cd ${KOKORO_ARTIFACTS_DIR}/github/java-spanner + +# Disable buffering, so that the logs stream through. +export PYTHONUNBUFFERED=1 + +# Kokoro exposes this as a file, but the scripts expect just a plain variable. +export GITHUB_TOKEN=$(cat ${KOKORO_KEYSTORE_DIR}/73713_yoshi-automation-github-key) + +# Setup git credentials +echo "https://${GITHUB_TOKEN}:@github.com" >> ~/.git-credentials +git config --global credential.helper 'store --file ~/.git-credentials' + +python3.6 -m pip install git+https://github.com/googleapis/synthtool.git#egg=gcp-synthtool +python3.6 -m autosynth.synth \ + --repository=googleapis/java-spanner \ + --synth-file-name=.github/readme/synth.py \ + --metadata-path=.github/readme/synth.metadata \ + --pr-title="chore: regenerate README" \ + --branch-suffix="readme" \ No newline at end of file diff --git a/synth.metadata b/synth.metadata index df6ac52a3a4..d47379a450e 100644 --- a/synth.metadata +++ b/synth.metadata @@ -4,7 +4,7 @@ "git": { "name": ".", "remote": "https://github.com/googleapis/java-spanner.git", - "sha": "e620a1572979efbcb25ef8adab3b60144e19f623" + "sha": "81b07e31a6a63a795d904094a72a6b51e593c314" } }, { @@ -19,7 +19,7 @@ "git": { "name": "synthtool", "remote": "https://github.com/googleapis/synthtool.git", - "sha": "95dbe1bee3c7f7e52ddb24a54c37080620e0d1a2" + "sha": "0762e8ee2ec21cdfc4d82020b985a104feb0453b" } } ], @@ -58,6 +58,7 @@ ".github/ISSUE_TEMPLATE/feature_request.md", ".github/ISSUE_TEMPLATE/support_request.md", ".github/PULL_REQUEST_TEMPLATE.md", + ".github/readme/synth.py", ".github/release-please.yml", ".github/trusted-contribution.yml", ".github/workflows/auto-release.yaml", @@ -69,6 +70,7 @@ ".kokoro/common.cfg", ".kokoro/common.sh", ".kokoro/continuous/java8.cfg", + ".kokoro/continuous/readme.cfg", ".kokoro/dependencies.sh", ".kokoro/linkage-monitor.sh", ".kokoro/nightly/integration.cfg", @@ -90,6 +92,7 @@ ".kokoro/presubmit/linkage-monitor.cfg", ".kokoro/presubmit/lint.cfg", ".kokoro/presubmit/samples.cfg", + ".kokoro/readme.sh", ".kokoro/release/bump_snapshot.cfg", ".kokoro/release/common.cfg", ".kokoro/release/common.sh", @@ -107,7 +110,6 @@ "CODE_OF_CONDUCT.md", "CONTRIBUTING.md", "LICENSE", - "README.md", "codecov.yaml", "google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminClient.java", "google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminSettings.java", From 20bce561cdffe985b23dedad3b9978e7f8ab4f5b Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Thu, 1 Oct 2020 10:50:05 -0700 Subject: [PATCH 16/19] chore: updates code owners (#464) This PR was generated using Autosynth. :rainbow: Synth log will be available here: https://source.cloud.google.com/results/invocations/fb04fd3e-7475-4b8c-9645-0272dcd0b593/targets - [ ] To automatically regenerate this PR, check this box. From 60fb986f8b758a65e20c5315faf85fc0a935d0cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Fri, 2 Oct 2020 01:42:39 +0200 Subject: [PATCH 17/19] fix: ResultSet#close() should not throw exceptions from session creation (#487) * fix: ResultSet#close() should not throw exceptions from session creation If a client application requested a session from the session pool, and that request required a new BatchCreateSessions request that would fail, then the error from the BatchCreateSessions RPC would be propagated to both the ReadContext#executeQuery(..) method as well as the ResultSet#close() method. The latter should not happen, as the close method should silently ignore any errors from the session creation. * docs: clear up comment --- .../cloud/spanner/ForwardingResultSet.java | 10 ++++++- .../com/google/cloud/spanner/SessionPool.java | 19 +++++++++++-- .../cloud/spanner/DatabaseClientImplTest.java | 27 +++++++++++++++++++ 3 files changed, 53 insertions(+), 3 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ForwardingResultSet.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ForwardingResultSet.java index 4cc0ab9b9e7..7d97fad162f 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ForwardingResultSet.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ForwardingResultSet.java @@ -61,7 +61,15 @@ public Struct getCurrentRowAsStruct() { @Override public void close() { - delegate.get().close(); + ResultSet rs; + try { + rs = delegate.get(); + } catch (Exception e) { + // Ignore any exceptions when getting the underlying result set, as that means that there is + // nothing that needs to be closed. + return; + } + rs.close(); } @Override diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPool.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPool.java index 90e399fad69..2512024117c 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPool.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPool.java @@ -1255,7 +1255,10 @@ public void close() { leakedException = null; checkedOutSessions.remove(this); } - get().close(); + PooledSession delegate = getOrNull(); + if (delegate != null) { + delegate.close(); + } } @Override @@ -1264,7 +1267,19 @@ public ApiFuture asyncClose() { leakedException = null; checkedOutSessions.remove(this); } - return get().asyncClose(); + PooledSession delegate = getOrNull(); + if (delegate != null) { + return delegate.asyncClose(); + } + return ApiFutures.immediateFuture(Empty.getDefaultInstance()); + } + + private PooledSession getOrNull() { + try { + return get(); + } catch (Throwable t) { + return null; + } } @Override diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java index bf425556b46..8775fb1b183 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java @@ -1599,4 +1599,31 @@ public Long run(TransactionContext transaction) throws Exception { } }); } + + @Test + public void testBatchCreateSessionsFailure_shouldNotPropagateToCloseMethod() { + try { + // Simulate session creation failures on the backend. + mockSpanner.setBatchCreateSessionsExecutionTime( + SimulatedExecutionTime.ofStickyException(Status.RESOURCE_EXHAUSTED.asRuntimeException())); + DatabaseClient client = + spannerWithEmptySessionPool.getDatabaseClient( + DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + // This will not cause any failure as getting a session from the pool is guaranteed to be + // non-blocking, and any exceptions will be delayed until actual query execution. + ResultSet rs = client.singleUse().executeQuery(SELECT1); + try { + while (rs.next()) { + fail("Missing expected exception"); + } + } catch (SpannerException e) { + assertThat(e.getErrorCode()).isEqualTo(ErrorCode.RESOURCE_EXHAUSTED); + } finally { + // This should not cause any failures. + rs.close(); + } + } finally { + mockSpanner.setBatchCreateSessionsExecutionTime(SimulatedExecutionTime.none()); + } + } } From be68019f315327fe587c3432c04ec87a519d82ab Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Fri, 2 Oct 2020 03:22:07 +0200 Subject: [PATCH 18/19] chore(deps): update dependency com.google.cloud.samples:shared-configuration to v1.0.21 (#490) --- samples/install-without-bom/pom.xml | 2 +- samples/pom.xml | 2 +- samples/snapshot/pom.xml | 2 +- samples/snippets/pom.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/samples/install-without-bom/pom.xml b/samples/install-without-bom/pom.xml index 79626289570..d4cca25d3ca 100644 --- a/samples/install-without-bom/pom.xml +++ b/samples/install-without-bom/pom.xml @@ -14,7 +14,7 @@ com.google.cloud.samples shared-configuration - 1.0.20 + 1.0.21 diff --git a/samples/pom.xml b/samples/pom.xml index 21a9eb1c126..b7ab0b1ca69 100644 --- a/samples/pom.xml +++ b/samples/pom.xml @@ -18,7 +18,7 @@ com.google.cloud.samples shared-configuration - 1.0.20 + 1.0.21 diff --git a/samples/snapshot/pom.xml b/samples/snapshot/pom.xml index 2dfe0f3c9fc..d14a02436db 100644 --- a/samples/snapshot/pom.xml +++ b/samples/snapshot/pom.xml @@ -14,7 +14,7 @@ com.google.cloud.samples shared-configuration - 1.0.20 + 1.0.21 diff --git a/samples/snippets/pom.xml b/samples/snippets/pom.xml index 5650c1f57ba..bb111adc0ee 100644 --- a/samples/snippets/pom.xml +++ b/samples/snippets/pom.xml @@ -14,7 +14,7 @@ com.google.cloud.samples shared-configuration - 1.0.20 + 1.0.21 From a6202e576b4ab2336e79538c2273b3caaa3a7f80 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Fri, 2 Oct 2020 12:33:00 +1000 Subject: [PATCH 19/19] chore: release 2.0.2 (#441) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- CHANGELOG.md | 15 +++++++++++++++ README.md | 4 ++-- google-cloud-spanner-bom/pom.xml | 18 +++++++++--------- google-cloud-spanner/pom.xml | 4 ++-- .../pom.xml | 4 ++-- .../pom.xml | 4 ++-- grpc-google-cloud-spanner-v1/pom.xml | 4 ++-- pom.xml | 16 ++++++++-------- .../pom.xml | 4 ++-- .../pom.xml | 4 ++-- proto-google-cloud-spanner-v1/pom.xml | 4 ++-- samples/snapshot/pom.xml | 2 +- versions.txt | 14 +++++++------- 13 files changed, 56 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d7f478282e7..9e23ca8a48f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +### [2.0.2](https://www.github.com/googleapis/java-spanner/compare/v2.0.1...v2.0.2) (2020-10-02) + + +### Bug Fixes + +* improve numeric range checks ([#424](https://www.github.com/googleapis/java-spanner/issues/424)) ([9f26785](https://www.github.com/googleapis/java-spanner/commit/9f2678568be77e82c14632b1c7ffcaafb71e7679)) +* ResultSet#close() should not throw exceptions from session creation ([#487](https://www.github.com/googleapis/java-spanner/issues/487)) ([60fb986](https://www.github.com/googleapis/java-spanner/commit/60fb986f8b758a65e20c5315faf85fc0a935d0cc)) +* skip failing backup tests for now ([#463](https://www.github.com/googleapis/java-spanner/issues/463)) ([f037f2d](https://www.github.com/googleapis/java-spanner/commit/f037f2d28096cd173ba338a966fd16babe8c697e)) +* use credentials key in pool ([#430](https://www.github.com/googleapis/java-spanner/issues/430)) ([28103fb](https://www.github.com/googleapis/java-spanner/commit/28103fb2d6e293d20399ecdfd680be67d9d62a1c)) + + +### Dependencies + +* update dependency com.google.cloud:google-cloud-shared-dependencies to v0.10.0 ([#453](https://www.github.com/googleapis/java-spanner/issues/453)) ([e05ee0e](https://www.github.com/googleapis/java-spanner/commit/e05ee0eaa16984393b60fc47f94412e560c36ff1)) + ### [2.0.1](https://www.github.com/googleapis/java-spanner/compare/v2.0.0...v2.0.1) (2020-09-18) diff --git a/README.md b/README.md index 40b9969a4bc..5a6157bea33 100644 --- a/README.md +++ b/README.md @@ -47,11 +47,11 @@ If you are using Maven without BOM, add this to your dependencies: If you are using Gradle, add this to your dependencies ```Groovy -compile 'com.google.cloud:google-cloud-spanner:2.0.1' +compile 'com.google.cloud:google-cloud-spanner:2.0.2' ``` If you are using SBT, add this to your dependencies ```Scala -libraryDependencies += "com.google.cloud" % "google-cloud-spanner" % "2.0.1" +libraryDependencies += "com.google.cloud" % "google-cloud-spanner" % "2.0.2" ``` [//]: # ({x-version-update-end}) diff --git a/google-cloud-spanner-bom/pom.xml b/google-cloud-spanner-bom/pom.xml index 3c191c2902c..2ed27bee666 100644 --- a/google-cloud-spanner-bom/pom.xml +++ b/google-cloud-spanner-bom/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.google.cloud google-cloud-spanner-bom - 2.0.2-SNAPSHOT + 2.0.2 pom com.google.cloud @@ -64,43 +64,43 @@ com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 2.0.2-SNAPSHOT + 2.0.2 com.google.api.grpc grpc-google-cloud-spanner-v1 - 2.0.2-SNAPSHOT + 2.0.2 com.google.api.grpc proto-google-cloud-spanner-v1 - 2.0.2-SNAPSHOT + 2.0.2 com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 2.0.2-SNAPSHOT + 2.0.2 com.google.cloud google-cloud-spanner - 2.0.2-SNAPSHOT + 2.0.2 com.google.cloud google-cloud-spanner test-jar - 2.0.2-SNAPSHOT + 2.0.2 com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 2.0.2-SNAPSHOT + 2.0.2 com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 2.0.2-SNAPSHOT + 2.0.2 diff --git a/google-cloud-spanner/pom.xml b/google-cloud-spanner/pom.xml index eca5aefb0bf..326f5e077d5 100644 --- a/google-cloud-spanner/pom.xml +++ b/google-cloud-spanner/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.google.cloud google-cloud-spanner - 2.0.2-SNAPSHOT + 2.0.2 jar Google Cloud Spanner https://github.com/googleapis/java-spanner @@ -11,7 +11,7 @@ com.google.cloud google-cloud-spanner-parent - 2.0.2-SNAPSHOT + 2.0.2 google-cloud-spanner diff --git a/grpc-google-cloud-spanner-admin-database-v1/pom.xml b/grpc-google-cloud-spanner-admin-database-v1/pom.xml index 1d75aa339e1..e845ba03e14 100644 --- a/grpc-google-cloud-spanner-admin-database-v1/pom.xml +++ b/grpc-google-cloud-spanner-admin-database-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 2.0.2-SNAPSHOT + 2.0.2 grpc-google-cloud-spanner-admin-database-v1 GRPC library for grpc-google-cloud-spanner-admin-database-v1 com.google.cloud google-cloud-spanner-parent - 2.0.2-SNAPSHOT + 2.0.2 diff --git a/grpc-google-cloud-spanner-admin-instance-v1/pom.xml b/grpc-google-cloud-spanner-admin-instance-v1/pom.xml index 9fc40770a43..9f51e34edf6 100644 --- a/grpc-google-cloud-spanner-admin-instance-v1/pom.xml +++ b/grpc-google-cloud-spanner-admin-instance-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 2.0.2-SNAPSHOT + 2.0.2 grpc-google-cloud-spanner-admin-instance-v1 GRPC library for grpc-google-cloud-spanner-admin-instance-v1 com.google.cloud google-cloud-spanner-parent - 2.0.2-SNAPSHOT + 2.0.2 diff --git a/grpc-google-cloud-spanner-v1/pom.xml b/grpc-google-cloud-spanner-v1/pom.xml index 616c73dd933..af4bfaad72d 100644 --- a/grpc-google-cloud-spanner-v1/pom.xml +++ b/grpc-google-cloud-spanner-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-spanner-v1 - 2.0.2-SNAPSHOT + 2.0.2 grpc-google-cloud-spanner-v1 GRPC library for grpc-google-cloud-spanner-v1 com.google.cloud google-cloud-spanner-parent - 2.0.2-SNAPSHOT + 2.0.2 diff --git a/pom.xml b/pom.xml index 2d8e95c650b..08df301b8a1 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.google.cloud google-cloud-spanner-parent pom - 2.0.2-SNAPSHOT + 2.0.2 Google Cloud Spanner Parent https://github.com/googleapis/java-spanner @@ -70,37 +70,37 @@ com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 2.0.2-SNAPSHOT + 2.0.2 com.google.api.grpc proto-google-cloud-spanner-v1 - 2.0.2-SNAPSHOT + 2.0.2 com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 2.0.2-SNAPSHOT + 2.0.2 com.google.api.grpc grpc-google-cloud-spanner-v1 - 2.0.2-SNAPSHOT + 2.0.2 com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 2.0.2-SNAPSHOT + 2.0.2 com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 2.0.2-SNAPSHOT + 2.0.2 com.google.cloud google-cloud-spanner - 2.0.2-SNAPSHOT + 2.0.2 diff --git a/proto-google-cloud-spanner-admin-database-v1/pom.xml b/proto-google-cloud-spanner-admin-database-v1/pom.xml index 8ce39c38b35..d7105cc7b8c 100644 --- a/proto-google-cloud-spanner-admin-database-v1/pom.xml +++ b/proto-google-cloud-spanner-admin-database-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 2.0.2-SNAPSHOT + 2.0.2 proto-google-cloud-spanner-admin-database-v1 PROTO library for proto-google-cloud-spanner-admin-database-v1 com.google.cloud google-cloud-spanner-parent - 2.0.2-SNAPSHOT + 2.0.2 diff --git a/proto-google-cloud-spanner-admin-instance-v1/pom.xml b/proto-google-cloud-spanner-admin-instance-v1/pom.xml index f6e85dacbfd..4f7e0889dc9 100644 --- a/proto-google-cloud-spanner-admin-instance-v1/pom.xml +++ b/proto-google-cloud-spanner-admin-instance-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 2.0.2-SNAPSHOT + 2.0.2 proto-google-cloud-spanner-admin-instance-v1 PROTO library for proto-google-cloud-spanner-admin-instance-v1 com.google.cloud google-cloud-spanner-parent - 2.0.2-SNAPSHOT + 2.0.2 diff --git a/proto-google-cloud-spanner-v1/pom.xml b/proto-google-cloud-spanner-v1/pom.xml index 6f263f9b0de..fd8dc8dff1a 100644 --- a/proto-google-cloud-spanner-v1/pom.xml +++ b/proto-google-cloud-spanner-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-spanner-v1 - 2.0.2-SNAPSHOT + 2.0.2 proto-google-cloud-spanner-v1 PROTO library for proto-google-cloud-spanner-v1 com.google.cloud google-cloud-spanner-parent - 2.0.2-SNAPSHOT + 2.0.2 diff --git a/samples/snapshot/pom.xml b/samples/snapshot/pom.xml index d14a02436db..39e2fe08dd2 100644 --- a/samples/snapshot/pom.xml +++ b/samples/snapshot/pom.xml @@ -28,7 +28,7 @@ com.google.cloud google-cloud-spanner - 2.0.2-SNAPSHOT + 2.0.2 diff --git a/versions.txt b/versions.txt index 3e90a37327f..fc1a2c984fc 100644 --- a/versions.txt +++ b/versions.txt @@ -1,10 +1,10 @@ # Format: # module:released-version:current-version -proto-google-cloud-spanner-admin-instance-v1:2.0.1:2.0.2-SNAPSHOT -proto-google-cloud-spanner-v1:2.0.1:2.0.2-SNAPSHOT -proto-google-cloud-spanner-admin-database-v1:2.0.1:2.0.2-SNAPSHOT -grpc-google-cloud-spanner-v1:2.0.1:2.0.2-SNAPSHOT -grpc-google-cloud-spanner-admin-instance-v1:2.0.1:2.0.2-SNAPSHOT -grpc-google-cloud-spanner-admin-database-v1:2.0.1:2.0.2-SNAPSHOT -google-cloud-spanner:2.0.1:2.0.2-SNAPSHOT \ No newline at end of file +proto-google-cloud-spanner-admin-instance-v1:2.0.2:2.0.2 +proto-google-cloud-spanner-v1:2.0.2:2.0.2 +proto-google-cloud-spanner-admin-database-v1:2.0.2:2.0.2 +grpc-google-cloud-spanner-v1:2.0.2:2.0.2 +grpc-google-cloud-spanner-admin-instance-v1:2.0.2:2.0.2 +grpc-google-cloud-spanner-admin-database-v1:2.0.2:2.0.2 +google-cloud-spanner:2.0.2:2.0.2 \ No newline at end of file