diff --git a/google-cloud-spanner/pom.xml b/google-cloud-spanner/pom.xml
index 77ab722be3..ad37f479a9 100644
--- a/google-cloud-spanner/pom.xml
+++ b/google-cloud-spanner/pom.xml
@@ -15,7 +15,6 @@
google-cloud-spanner
- false
@@ -51,7 +50,6 @@
default-test
com.google.cloud.spanner.TracerTest,com.google.cloud.spanner.IntegrationTest
- ${skipUTs}
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java
index 62cfa336e9..88587c6428 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java
@@ -104,6 +104,7 @@ public class SpannerOptions extends ServiceOptions {
private final DatabaseAdminStubSettings databaseAdminStubSettings;
private final Duration partitionedDmlTimeout;
private final boolean autoThrottleAdministrativeRequests;
+ private final RetrySettings retryAdministrativeRequestsSettings;
private final boolean trackTransactionStarter;
/**
* These are the default {@link QueryOptions} defined by the user on this {@link SpannerOptions}.
@@ -554,6 +555,7 @@ private SpannerOptions(Builder builder) {
}
partitionedDmlTimeout = builder.partitionedDmlTimeout;
autoThrottleAdministrativeRequests = builder.autoThrottleAdministrativeRequests;
+ retryAdministrativeRequestsSettings = builder.retryAdministrativeRequestsSettings;
trackTransactionStarter = builder.trackTransactionStarter;
defaultQueryOptions = builder.defaultQueryOptions;
envQueryOptions = builder.getEnvironmentQueryOptions();
@@ -606,6 +608,13 @@ public static class Builder
extends ServiceOptions.Builder {
static final int DEFAULT_PREFETCH_CHUNKS = 4;
static final QueryOptions DEFAULT_QUERY_OPTIONS = QueryOptions.getDefaultInstance();
+ static final RetrySettings DEFAULT_ADMIN_REQUESTS_LIMIT_EXCEEDED_RETRY_SETTINGS =
+ RetrySettings.newBuilder()
+ .setInitialRetryDelay(Duration.ofSeconds(5L))
+ .setRetryDelayMultiplier(2.0)
+ .setMaxRetryDelay(Duration.ofSeconds(60L))
+ .setMaxAttempts(10)
+ .build();
private final ImmutableSet allowedClientLibTokens =
ImmutableSet.of(
ServiceOptions.getGoogApiClientLibName(),
@@ -632,6 +641,8 @@ public static class Builder
private DatabaseAdminStubSettings.Builder databaseAdminStubSettingsBuilder =
DatabaseAdminStubSettings.newBuilder();
private Duration partitionedDmlTimeout = Duration.ofHours(2L);
+ private RetrySettings retryAdministrativeRequestsSettings =
+ DEFAULT_ADMIN_REQUESTS_LIMIT_EXCEEDED_RETRY_SETTINGS;
private boolean autoThrottleAdministrativeRequests = false;
private boolean trackTransactionStarter = false;
private Map defaultQueryOptions = new HashMap<>();
@@ -680,6 +691,7 @@ private Builder() {
this.databaseAdminStubSettingsBuilder = options.databaseAdminStubSettings.toBuilder();
this.partitionedDmlTimeout = options.partitionedDmlTimeout;
this.autoThrottleAdministrativeRequests = options.autoThrottleAdministrativeRequests;
+ this.retryAdministrativeRequestsSettings = options.retryAdministrativeRequestsSettings;
this.trackTransactionStarter = options.trackTransactionStarter;
this.defaultQueryOptions = options.defaultQueryOptions;
this.callCredentialsProvider = options.callCredentialsProvider;
@@ -892,6 +904,16 @@ public Builder setAutoThrottleAdministrativeRequests() {
return this;
}
+ /**
+ * Sets the retry settings for retrying administrative requests when the quote of administrative
+ * requests per minute has been exceeded.
+ */
+ Builder setRetryAdministrativeRequestsSettings(
+ RetrySettings retryAdministrativeRequestsSettings) {
+ this.retryAdministrativeRequestsSettings = retryAdministrativeRequestsSettings;
+ return this;
+ }
+
/**
* Instructs the client library to track the first request of each read/write transaction. This
* statement will include a BeginTransaction option and will return a transaction id as part of
@@ -1092,6 +1114,10 @@ public boolean isAutoThrottleAdministrativeRequests() {
return autoThrottleAdministrativeRequests;
}
+ public RetrySettings getRetryAdministrativeRequestsSettings() {
+ return retryAdministrativeRequestsSettings;
+ }
+
public boolean isTrackTransactionStarter() {
return trackTransactionStarter;
}
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java
index 29ee44bede..ef7966beed 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java
@@ -273,6 +273,7 @@ private void awaitTermination() throws InterruptedException {
private final ScheduledExecutorService spannerWatchdog;
private final boolean throttleAdministrativeRequests;
+ private final RetrySettings retryAdministrativeRequestsSettings;
private static final double ADMINISTRATIVE_REQUESTS_RATE_LIMIT = 1.0D;
private static final ConcurrentMap ADMINISTRATIVE_REQUESTS_RATE_LIMITERS =
new ConcurrentHashMap<>();
@@ -282,6 +283,10 @@ public static GapicSpannerRpc create(SpannerOptions options) {
}
public GapicSpannerRpc(final SpannerOptions options) {
+ this(options, true);
+ }
+
+ GapicSpannerRpc(final SpannerOptions options, boolean initializeStubs) {
this.projectId = options.getProjectId();
String projectNameStr = PROJECT_NAME_TEMPLATE.instantiate("project", this.projectId);
try {
@@ -296,6 +301,7 @@ public GapicSpannerRpc(final SpannerOptions options) {
ADMINISTRATIVE_REQUESTS_RATE_LIMITERS.putIfAbsent(
projectNameStr, RateLimiter.create(ADMINISTRATIVE_REQUESTS_RATE_LIMIT));
}
+ this.retryAdministrativeRequestsSettings = options.getRetryAdministrativeRequestsSettings();
// create a metadataProvider which combines both internal headers and
// per-method-call extra headers for channelProvider to inject the headers
@@ -322,173 +328,184 @@ public GapicSpannerRpc(final SpannerOptions options) {
this.callCredentialsProvider = options.getCallCredentialsProvider();
this.compressorName = options.getCompressorName();
- // Create a managed executor provider.
- this.executorProvider =
- new ManagedInstantiatingExecutorProvider(
- new ThreadFactoryBuilder()
- .setDaemon(true)
- .setNameFormat("Cloud-Spanner-TransportChannel-%d")
- .build());
- // First check if SpannerOptions provides a TransportChannelProvider. Create one
- // with information gathered from SpannerOptions if none is provided
- InstantiatingGrpcChannelProvider.Builder defaultChannelProviderBuilder =
- InstantiatingGrpcChannelProvider.newBuilder()
- .setChannelConfigurator(options.getChannelConfigurator())
- .setEndpoint(options.getEndpoint())
- .setMaxInboundMessageSize(MAX_MESSAGE_SIZE)
- .setMaxInboundMetadataSize(MAX_METADATA_SIZE)
- .setPoolSize(options.getNumChannels())
-
- // Before updating this method to setExecutor, please verify with a code owner on
- // the lowest version of gax-grpc that needs to be supported. Currently v1.47.17,
- // which doesn't support the setExecutor variant.
- .setExecutorProvider(executorProvider)
-
- // Set a keepalive time of 120 seconds to help long running
- // commit GRPC calls succeed
- .setKeepAliveTime(Duration.ofSeconds(GRPC_KEEPALIVE_SECONDS))
-
- // Then check if SpannerOptions provides an InterceptorProvider. Create a default
- // SpannerInterceptorProvider if none is provided
- .setInterceptorProvider(
- SpannerInterceptorProvider.create(
- MoreObjects.firstNonNull(
- options.getInterceptorProvider(),
- SpannerInterceptorProvider.createDefault()))
- .withEncoding(compressorName))
- .setHeaderProvider(headerProviderWithUserAgent)
- // Attempts direct access to spanner service over gRPC to improve throughput,
- // whether the attempt is allowed is totally controlled by service owner.
- .setAttemptDirectPath(true);
-
- TransportChannelProvider channelProvider =
- MoreObjects.firstNonNull(
- options.getChannelProvider(), defaultChannelProviderBuilder.build());
-
- CredentialsProvider credentialsProvider =
- GrpcTransportOptions.setUpCredentialsProvider(options);
-
- spannerWatchdog =
- Executors.newSingleThreadScheduledExecutor(
- new ThreadFactoryBuilder()
- .setDaemon(true)
- .setNameFormat("Cloud-Spanner-WatchdogProvider-%d")
- .build());
- WatchdogProvider watchdogProvider =
- InstantiatingWatchdogProvider.create()
- .withExecutor(spannerWatchdog)
- .withCheckInterval(checkInterval)
- .withClock(NanoClock.getDefaultClock());
-
- try {
- this.spannerStub =
- GrpcSpannerStub.create(
- options
- .getSpannerStubSettings()
- .toBuilder()
- .setTransportChannelProvider(channelProvider)
- .setCredentialsProvider(credentialsProvider)
- .setStreamWatchdogProvider(watchdogProvider)
+ if (initializeStubs) {
+ // Create a managed executor provider.
+ this.executorProvider =
+ new ManagedInstantiatingExecutorProvider(
+ new ThreadFactoryBuilder()
+ .setDaemon(true)
+ .setNameFormat("Cloud-Spanner-TransportChannel-%d")
.build());
- partitionedDmlRetrySettings =
- options
- .getSpannerStubSettings()
- .executeSqlSettings()
- .getRetrySettings()
- .toBuilder()
- .setInitialRpcTimeout(options.getPartitionedDmlTimeout())
- .setMaxRpcTimeout(options.getPartitionedDmlTimeout())
- .setTotalTimeout(options.getPartitionedDmlTimeout())
- .setRpcTimeoutMultiplier(1.0)
- .build();
- SpannerStubSettings.Builder pdmlSettings = options.getSpannerStubSettings().toBuilder();
- pdmlSettings
- .setTransportChannelProvider(channelProvider)
- .setCredentialsProvider(credentialsProvider)
- .setStreamWatchdogProvider(watchdogProvider)
- .executeSqlSettings()
- .setRetrySettings(partitionedDmlRetrySettings);
- pdmlSettings.executeStreamingSqlSettings().setRetrySettings(partitionedDmlRetrySettings);
- // The stream watchdog will by default only check for a timeout every 10 seconds, so if the
- // timeout is less than 10 seconds, it would be ignored for the first 10 seconds unless we
- // also change the StreamWatchdogCheckInterval.
- if (options
- .getPartitionedDmlTimeout()
- .dividedBy(10L)
- .compareTo(pdmlSettings.getStreamWatchdogCheckInterval())
- < 0) {
- pdmlSettings.setStreamWatchdogCheckInterval(
- options.getPartitionedDmlTimeout().dividedBy(10));
- pdmlSettings.setStreamWatchdogProvider(
- pdmlSettings
- .getStreamWatchdogProvider()
- .withCheckInterval(pdmlSettings.getStreamWatchdogCheckInterval()));
- }
- this.partitionedDmlStub = GrpcSpannerStub.create(pdmlSettings.build());
-
- this.instanceAdminStub =
- GrpcInstanceAdminStub.create(
- options
- .getInstanceAdminStubSettings()
- .toBuilder()
- .setTransportChannelProvider(channelProvider)
- .setCredentialsProvider(credentialsProvider)
- .setStreamWatchdogProvider(watchdogProvider)
+ // First check if SpannerOptions provides a TransportChannelProvider. Create one
+ // with information gathered from SpannerOptions if none is provided
+ InstantiatingGrpcChannelProvider.Builder defaultChannelProviderBuilder =
+ InstantiatingGrpcChannelProvider.newBuilder()
+ .setChannelConfigurator(options.getChannelConfigurator())
+ .setEndpoint(options.getEndpoint())
+ .setMaxInboundMessageSize(MAX_MESSAGE_SIZE)
+ .setMaxInboundMetadataSize(MAX_METADATA_SIZE)
+ .setPoolSize(options.getNumChannels())
+
+ // Before updating this method to setExecutor, please verify with a code owner on
+ // the lowest version of gax-grpc that needs to be supported. Currently v1.47.17,
+ // which doesn't support the setExecutor variant.
+ .setExecutorProvider(executorProvider)
+
+ // Set a keepalive time of 120 seconds to help long running
+ // commit GRPC calls succeed
+ .setKeepAliveTime(Duration.ofSeconds(GRPC_KEEPALIVE_SECONDS))
+
+ // Then check if SpannerOptions provides an InterceptorProvider. Create a default
+ // SpannerInterceptorProvider if none is provided
+ .setInterceptorProvider(
+ SpannerInterceptorProvider.create(
+ MoreObjects.firstNonNull(
+ options.getInterceptorProvider(),
+ SpannerInterceptorProvider.createDefault()))
+ .withEncoding(compressorName))
+ .setHeaderProvider(headerProviderWithUserAgent)
+ // Attempts direct access to spanner service over gRPC to improve throughput,
+ // whether the attempt is allowed is totally controlled by service owner.
+ .setAttemptDirectPath(true);
+
+ TransportChannelProvider channelProvider =
+ MoreObjects.firstNonNull(
+ options.getChannelProvider(), defaultChannelProviderBuilder.build());
+
+ CredentialsProvider credentialsProvider =
+ GrpcTransportOptions.setUpCredentialsProvider(options);
+
+ spannerWatchdog =
+ Executors.newSingleThreadScheduledExecutor(
+ new ThreadFactoryBuilder()
+ .setDaemon(true)
+ .setNameFormat("Cloud-Spanner-WatchdogProvider-%d")
.build());
+ WatchdogProvider watchdogProvider =
+ InstantiatingWatchdogProvider.create()
+ .withExecutor(spannerWatchdog)
+ .withCheckInterval(checkInterval)
+ .withClock(NanoClock.getDefaultClock());
- this.databaseAdminStubSettings =
- options
- .getDatabaseAdminStubSettings()
- .toBuilder()
- .setTransportChannelProvider(channelProvider)
- .setCredentialsProvider(credentialsProvider)
- .setStreamWatchdogProvider(watchdogProvider)
- .build();
-
- // Automatically retry RESOURCE_EXHAUSTED for GetOperation if auto-throttling of
- // administrative requests has been set. The GetOperation RPC is called repeatedly by gax
- // while polling long-running operations for their progress and can also cause these errors.
- // The default behavior is not to retry these errors, and this option should normally only be
- // enabled for (integration) testing.
- if (options.isAutoThrottleAdministrativeRequests()) {
- GrpcStubCallableFactory factory =
- new GrpcDatabaseAdminCallableFactory() {
- @Override
- public UnaryCallable createUnaryCallable(
- GrpcCallSettings grpcCallSettings,
- UnaryCallSettings callSettings,
- ClientContext clientContext) {
- // Make GetOperation retry on RESOURCE_EXHAUSTED to prevent polling operations from
- // failing with an Administrative requests limit exceeded error.
- if (grpcCallSettings
- .getMethodDescriptor()
- .getFullMethodName()
- .equals("google.longrunning.Operations/GetOperation")) {
- Set codes =
- ImmutableSet.builderWithExpectedSize(
- callSettings.getRetryableCodes().size() + 1)
- .addAll(callSettings.getRetryableCodes())
- .add(StatusCode.Code.RESOURCE_EXHAUSTED)
- .build();
- callSettings = callSettings.toBuilder().setRetryableCodes(codes).build();
+ try {
+ this.spannerStub =
+ GrpcSpannerStub.create(
+ options
+ .getSpannerStubSettings()
+ .toBuilder()
+ .setTransportChannelProvider(channelProvider)
+ .setCredentialsProvider(credentialsProvider)
+ .setStreamWatchdogProvider(watchdogProvider)
+ .build());
+ partitionedDmlRetrySettings =
+ options
+ .getSpannerStubSettings()
+ .executeSqlSettings()
+ .getRetrySettings()
+ .toBuilder()
+ .setInitialRpcTimeout(options.getPartitionedDmlTimeout())
+ .setMaxRpcTimeout(options.getPartitionedDmlTimeout())
+ .setTotalTimeout(options.getPartitionedDmlTimeout())
+ .setRpcTimeoutMultiplier(1.0)
+ .build();
+ SpannerStubSettings.Builder pdmlSettings = options.getSpannerStubSettings().toBuilder();
+ pdmlSettings
+ .setTransportChannelProvider(channelProvider)
+ .setCredentialsProvider(credentialsProvider)
+ .setStreamWatchdogProvider(watchdogProvider)
+ .executeSqlSettings()
+ .setRetrySettings(partitionedDmlRetrySettings);
+ pdmlSettings.executeStreamingSqlSettings().setRetrySettings(partitionedDmlRetrySettings);
+ // The stream watchdog will by default only check for a timeout every 10 seconds, so if the
+ // timeout is less than 10 seconds, it would be ignored for the first 10 seconds unless we
+ // also change the StreamWatchdogCheckInterval.
+ if (options
+ .getPartitionedDmlTimeout()
+ .dividedBy(10L)
+ .compareTo(pdmlSettings.getStreamWatchdogCheckInterval())
+ < 0) {
+ pdmlSettings.setStreamWatchdogCheckInterval(
+ options.getPartitionedDmlTimeout().dividedBy(10));
+ pdmlSettings.setStreamWatchdogProvider(
+ pdmlSettings
+ .getStreamWatchdogProvider()
+ .withCheckInterval(pdmlSettings.getStreamWatchdogCheckInterval()));
+ }
+ this.partitionedDmlStub = GrpcSpannerStub.create(pdmlSettings.build());
+
+ this.instanceAdminStub =
+ GrpcInstanceAdminStub.create(
+ options
+ .getInstanceAdminStubSettings()
+ .toBuilder()
+ .setTransportChannelProvider(channelProvider)
+ .setCredentialsProvider(credentialsProvider)
+ .setStreamWatchdogProvider(watchdogProvider)
+ .build());
+
+ this.databaseAdminStubSettings =
+ options
+ .getDatabaseAdminStubSettings()
+ .toBuilder()
+ .setTransportChannelProvider(channelProvider)
+ .setCredentialsProvider(credentialsProvider)
+ .setStreamWatchdogProvider(watchdogProvider)
+ .build();
+
+ // Automatically retry RESOURCE_EXHAUSTED for GetOperation if auto-throttling of
+ // administrative requests has been set. The GetOperation RPC is called repeatedly by gax
+ // while polling long-running operations for their progress and can also cause these errors.
+ // The default behavior is not to retry these errors, and this option should normally only
+ // be enabled for (integration) testing.
+ if (options.isAutoThrottleAdministrativeRequests()) {
+ GrpcStubCallableFactory factory =
+ new GrpcDatabaseAdminCallableFactory() {
+ @Override
+ public UnaryCallable createUnaryCallable(
+ GrpcCallSettings grpcCallSettings,
+ UnaryCallSettings callSettings,
+ ClientContext clientContext) {
+ // Make GetOperation retry on RESOURCE_EXHAUSTED to prevent polling operations
+ // from failing with an Administrative requests limit exceeded error.
+ if (grpcCallSettings
+ .getMethodDescriptor()
+ .getFullMethodName()
+ .equals("google.longrunning.Operations/GetOperation")) {
+ Set codes =
+ ImmutableSet.builderWithExpectedSize(
+ callSettings.getRetryableCodes().size() + 1)
+ .addAll(callSettings.getRetryableCodes())
+ .add(StatusCode.Code.RESOURCE_EXHAUSTED)
+ .build();
+ callSettings = callSettings.toBuilder().setRetryableCodes(codes).build();
+ }
+ return super.createUnaryCallable(grpcCallSettings, callSettings, clientContext);
}
- return super.createUnaryCallable(grpcCallSettings, callSettings, clientContext);
- }
- };
- this.databaseAdminStub =
- new GrpcDatabaseAdminStubWithCustomCallableFactory(
- databaseAdminStubSettings,
- ClientContext.create(databaseAdminStubSettings),
- factory);
- } else {
- this.databaseAdminStub = GrpcDatabaseAdminStub.create(databaseAdminStubSettings);
- }
+ };
+ this.databaseAdminStub =
+ new GrpcDatabaseAdminStubWithCustomCallableFactory(
+ databaseAdminStubSettings,
+ ClientContext.create(databaseAdminStubSettings),
+ factory);
+ } else {
+ this.databaseAdminStub = GrpcDatabaseAdminStub.create(databaseAdminStubSettings);
+ }
- // Check whether the SPANNER_EMULATOR_HOST env var has been set, and if so, if the emulator is
- // actually running.
- checkEmulatorConnection(options, channelProvider, credentialsProvider);
- } catch (Exception e) {
- throw newSpannerException(e);
+ // Check whether the SPANNER_EMULATOR_HOST env var has been set, and if so, if the emulator
+ // is actually running.
+ checkEmulatorConnection(options, channelProvider, credentialsProvider);
+ } catch (Exception e) {
+ throw newSpannerException(e);
+ }
+ } else {
+ this.databaseAdminStub = null;
+ this.instanceAdminStub = null;
+ this.spannerStub = null;
+ this.partitionedDmlStub = null;
+ this.databaseAdminStubSettings = null;
+ this.spannerWatchdog = null;
+ this.partitionedDmlRetrySettings = null;
+ this.executorProvider = null;
}
}
@@ -578,11 +595,11 @@ public boolean shouldRetry(Throwable prevThrowable, T prevResponse)
}
}
- private static T runWithRetryOnAdministrativeRequestsExceeded(Callable callable) {
+ private T runWithRetryOnAdministrativeRequestsExceeded(Callable callable) {
try {
return RetryHelper.runWithRetries(
callable,
- ADMIN_REQUESTS_LIMIT_EXCEEDED_RETRY_SETTINGS,
+ retryAdministrativeRequestsSettings,
new AdminRequestsLimitExceededRetryAlgorithm<>(),
NanoClock.getDefaultClock());
} catch (RetryHelperException e) {
@@ -1630,22 +1647,24 @@ GrpcCallContext newCallContext(
@Override
public void shutdown() {
this.rpcIsClosed = true;
- this.spannerStub.close();
- this.partitionedDmlStub.close();
- this.instanceAdminStub.close();
- this.databaseAdminStub.close();
- this.spannerWatchdog.shutdown();
- this.executorProvider.shutdown();
+ if (this.spannerStub != null) {
+ this.spannerStub.close();
+ this.partitionedDmlStub.close();
+ this.instanceAdminStub.close();
+ this.databaseAdminStub.close();
+ this.spannerWatchdog.shutdown();
+ this.executorProvider.shutdown();
- try {
- this.spannerStub.awaitTermination(10L, TimeUnit.SECONDS);
- this.partitionedDmlStub.awaitTermination(10L, TimeUnit.SECONDS);
- this.instanceAdminStub.awaitTermination(10L, TimeUnit.SECONDS);
- this.databaseAdminStub.awaitTermination(10L, TimeUnit.SECONDS);
- this.spannerWatchdog.awaitTermination(10L, TimeUnit.SECONDS);
- this.executorProvider.awaitTermination();
- } catch (InterruptedException e) {
- throw SpannerExceptionFactory.propagateInterrupt(e);
+ try {
+ this.spannerStub.awaitTermination(10L, TimeUnit.SECONDS);
+ this.partitionedDmlStub.awaitTermination(10L, TimeUnit.SECONDS);
+ this.instanceAdminStub.awaitTermination(10L, TimeUnit.SECONDS);
+ this.databaseAdminStub.awaitTermination(10L, TimeUnit.SECONDS);
+ this.spannerWatchdog.awaitTermination(10L, TimeUnit.SECONDS);
+ this.executorProvider.awaitTermination();
+ } catch (InterruptedException e) {
+ throw SpannerExceptionFactory.propagateInterrupt(e);
+ }
}
}
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientTest.java
index 3a18f24173..9dcadc85ad 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientTest.java
@@ -38,18 +38,22 @@
import com.google.cloud.spanner.MockSpannerServiceImpl.SimulatedExecutionTime;
import com.google.longrunning.Operation;
import com.google.protobuf.InvalidProtocolBufferException;
+import com.google.rpc.ErrorInfo;
import com.google.spanner.admin.database.v1.CreateBackupMetadata;
import com.google.spanner.admin.database.v1.CreateBackupRequest;
import com.google.spanner.admin.database.v1.CreateDatabaseMetadata;
import com.google.spanner.admin.database.v1.CreateDatabaseRequest;
+import com.google.spanner.admin.database.v1.GetDatabaseRequest;
import com.google.spanner.admin.database.v1.OptimizeRestoredDatabaseMetadata;
import com.google.spanner.admin.database.v1.RestoreDatabaseMetadata;
import com.google.spanner.admin.database.v1.RestoreDatabaseRequest;
import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata;
import io.grpc.ManagedChannelBuilder;
+import io.grpc.Metadata;
import io.grpc.Server;
import io.grpc.Status;
import io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder;
+import io.grpc.protobuf.lite.ProtoLiteUtils;
import java.net.InetSocketAddress;
import java.util.Arrays;
import java.util.Collections;
@@ -83,8 +87,8 @@ public class DatabaseAdminClientTest {
private static Server server;
private static InetSocketAddress address;
- private Spanner spanner;
- private DatabaseAdminClient client;
+ private static Spanner spanner;
+ private static DatabaseAdminClient client;
private OperationFuture createDatabaseOperation;
private OperationFuture createBackupOperation;
private OperationFuture restoreDatabaseOperation;
@@ -101,18 +105,6 @@ public static void startStaticServer() throws Exception {
.addService(mockDatabaseAdmin)
.build()
.start();
- }
-
- @AfterClass
- public static void stopServer() throws Exception {
- server.shutdown();
- server.awaitTermination();
- }
-
- @Before
- public void setUp() {
- mockDatabaseAdmin.reset();
- mockOperations.reset();
SpannerOptions.Builder builder = SpannerOptions.newBuilder();
RetrySettings longRunningInitialRetrySettings =
RetrySettings.newBuilder()
@@ -193,6 +185,11 @@ public void setUp() {
.setRetryDelayMultiplier(1.3)
.setRpcTimeoutMultiplier(1.3)
.build()));
+ builder.setRetryAdministrativeRequestsSettings(
+ SpannerOptions.Builder.DEFAULT_ADMIN_REQUESTS_LIMIT_EXCEEDED_RETRY_SETTINGS
+ .toBuilder()
+ .setInitialRetryDelay(Duration.ofNanos(1L))
+ .build());
spanner =
builder
.setHost("http://localhost:" + server.getPort())
@@ -202,6 +199,19 @@ public void setUp() {
.build()
.getService();
client = spanner.getDatabaseAdminClient();
+ }
+
+ @AfterClass
+ public static void stopServer() throws Exception {
+ spanner.close();
+ server.shutdown();
+ server.awaitTermination();
+ }
+
+ @Before
+ public void setUp() {
+ mockDatabaseAdmin.reset();
+ mockOperations.reset();
createTestDatabase();
createTestBackup();
restoreTestBackup();
@@ -212,7 +222,6 @@ public void tearDown() {
mockDatabaseAdmin.reset();
mockDatabaseAdmin.removeAllExecutionTimes();
mockOperations.reset();
- spanner.close();
}
@Test
@@ -905,4 +914,25 @@ public void retryRestoreDatabaseSlowStartup() throws Exception {
assertThat(retrieved.getCreateTime()).isEqualTo(database.getCreateTime());
assertThat(mockDatabaseAdmin.countRequestsOfType(RestoreDatabaseRequest.class)).isAtLeast(3);
}
+
+ @Test
+ public void testRetryOperationOnAdminMethodQuotaPerMinutePerProjectExceeded() {
+ ErrorInfo info =
+ ErrorInfo.newBuilder()
+ .putMetadata("quota_limit", "AdminMethodQuotaPerMinutePerProject")
+ .build();
+ Metadata.Key key =
+ Metadata.Key.of(
+ info.getDescriptorForType().getFullName() + Metadata.BINARY_HEADER_SUFFIX,
+ ProtoLiteUtils.metadataMarshaller(info));
+ Metadata trailers = new Metadata();
+ trailers.put(key, info);
+ mockDatabaseAdmin.addException(
+ Status.RESOURCE_EXHAUSTED.withDescription("foo").asRuntimeException(trailers));
+ mockDatabaseAdmin.clearRequests();
+
+ Database database = client.getDatabase(INSTANCE_ID, DB_ID);
+ assertEquals(DB_ID, database.getId().getDatabase());
+ assertEquals(2, mockDatabaseAdmin.countRequestsOfType(GetDatabaseRequest.class));
+ }
}
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 891f226562..42c7bb1b94 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
@@ -958,6 +958,7 @@ public void transactionManagerIsNonBlocking() throws Exception {
}
}
+ @SuppressWarnings("resource")
@Test
public void transactionManagerExecuteQueryAsync() throws Exception {
DatabaseClient client =
@@ -991,7 +992,6 @@ public void transactionManagerExecuteQueryAsync() throws Exception {
txManager.commit();
break;
} catch (AbortedException e) {
- Thread.sleep(e.getRetryDelayInMillis());
transaction = txManager.resetForRetry();
}
}
@@ -1519,11 +1519,7 @@ public void testBackendQueryOptions() {
.setProjectId("[PROJECT]")
.setChannelProvider(channelProvider)
.setCredentials(NoCredentials.getInstance())
- .setSessionPoolOption(
- SessionPoolOptions.newBuilder()
- .setMinSessions(0)
- .setWriteSessionsFraction(0.0f)
- .build())
+ .setSessionPoolOption(SessionPoolOptions.newBuilder().setMinSessions(0).build())
.build()
.getService()) {
DatabaseClient client =
@@ -1557,11 +1553,7 @@ public void testBackendQueryOptionsWithAnalyzeQuery() {
.setProjectId("[PROJECT]")
.setChannelProvider(channelProvider)
.setCredentials(NoCredentials.getInstance())
- .setSessionPoolOption(
- SessionPoolOptions.newBuilder()
- .setMinSessions(0)
- .setWriteSessionsFraction(0.0f)
- .build())
+ .setSessionPoolOption(SessionPoolOptions.newBuilder().setMinSessions(0).build())
.build()
.getService()) {
DatabaseClient client =
@@ -1597,11 +1589,7 @@ public void testBackendPartitionQueryOptions() {
.setProjectId("[PROJECT]")
.setChannelProvider(channelProvider)
.setCredentials(NoCredentials.getInstance())
- .setSessionPoolOption(
- SessionPoolOptions.newBuilder()
- .setMinSessions(0)
- .setWriteSessionsFraction(0.0f)
- .build())
+ .setSessionPoolOption(SessionPoolOptions.newBuilder().setMinSessions(0).build())
.build()
.getService()) {
BatchClient client =
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MockDatabaseAdminServiceImpl.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MockDatabaseAdminServiceImpl.java
index 20a39f318f..6b248f7902 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MockDatabaseAdminServiceImpl.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MockDatabaseAdminServiceImpl.java
@@ -447,6 +447,7 @@ private com.google.rpc.Status fromException(Exception e) {
private SimulatedExecutionTime createDatabaseStartupExecutionTime = SimulatedExecutionTime.none();
private SimulatedExecutionTime createDatabaseResponseExecutionTime =
SimulatedExecutionTime.none();
+ private SimulatedExecutionTime getDatabaseExecutionTime = SimulatedExecutionTime.none();
private SimulatedExecutionTime restoreDatabaseStartupExecutionTime =
SimulatedExecutionTime.none();
private SimulatedExecutionTime restoreDatabaseResponseExecutionTime =
@@ -509,17 +510,22 @@ public void dropDatabase(DropDatabaseRequest request, StreamObserver resp
@Override
public void getDatabase(GetDatabaseRequest request, StreamObserver responseObserver) {
requests.add(request);
- MockDatabase db = databases.get(request.getName());
- if (db != null) {
- responseObserver.onNext(
- Database.newBuilder()
- .setName(request.getName())
- .setCreateTime(db.createTime)
- .setState(State.READY)
- .build());
- responseObserver.onCompleted();
- } else {
- responseObserver.onError(Status.NOT_FOUND.asRuntimeException());
+ try {
+ getDatabaseExecutionTime.simulateExecutionTime(exceptions, false, freezeLock);
+ MockDatabase db = databases.get(request.getName());
+ if (db != null) {
+ responseObserver.onNext(
+ Database.newBuilder()
+ .setName(request.getName())
+ .setCreateTime(db.createTime)
+ .setState(State.READY)
+ .build());
+ responseObserver.onCompleted();
+ } else {
+ responseObserver.onError(Status.NOT_FOUND.asRuntimeException());
+ }
+ } catch (Throwable t) {
+ responseObserver.onError(t);
}
}
@@ -912,6 +918,10 @@ public List getRequests() {
return new ArrayList<>(requests);
}
+ public void clearRequests() {
+ requests.clear();
+ }
+
public int countRequestsOfType(final Class extends AbstractMessage> type) {
return Collections2.filter(getRequests(), input -> input.getClass().equals(type)).size();
}
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/RetryOnInvalidatedSessionTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/RetryOnInvalidatedSessionTest.java
index d8eec88d88..a8fbbeb40b 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/RetryOnInvalidatedSessionTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/RetryOnInvalidatedSessionTest.java
@@ -18,10 +18,7 @@
import static com.google.cloud.spanner.SpannerApiFutures.get;
import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertThrows;
import static org.junit.Assert.fail;
import com.google.api.core.ApiFuture;
@@ -29,13 +26,11 @@
import com.google.api.gax.core.NoCredentialsProvider;
import com.google.api.gax.grpc.testing.LocalChannelProvider;
import com.google.cloud.NoCredentials;
-import com.google.cloud.Timestamp;
import com.google.cloud.spanner.AsyncResultSet.CallbackResponse;
import com.google.cloud.spanner.AsyncTransactionManager.AsyncTransactionStep;
import com.google.cloud.spanner.AsyncTransactionManager.CommitTimestampFuture;
import com.google.cloud.spanner.AsyncTransactionManager.TransactionContextFuture;
import com.google.cloud.spanner.MockSpannerServiceImpl.StatementResult;
-import com.google.cloud.spanner.TransactionRunner.TransactionCallable;
import com.google.cloud.spanner.v1.SpannerClient;
import com.google.cloud.spanner.v1.SpannerClient.ListSessionsPagedResponse;
import com.google.cloud.spanner.v1.SpannerSettings;
@@ -55,12 +50,12 @@
import java.util.Collection;
import java.util.Collections;
import java.util.List;
-import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
-import org.junit.After;
+import java.util.function.Supplier;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
@@ -208,30 +203,31 @@ public static void stopServer() throws InterruptedException {
}
@Before
- public void setUp() {
+ public void setUp() throws InterruptedException {
mockSpanner.reset();
- SessionPoolOptions.Builder builder = SessionPoolOptions.newBuilder().setFailOnSessionLeak();
- if (failOnInvalidatedSession) {
- builder.setFailIfSessionNotFound();
+ if (spanner == null
+ || spanner.getOptions().getSessionPoolOptions().isFailIfPoolExhausted()
+ != failOnInvalidatedSession) {
+ if (spanner != null) {
+ spanner.close();
+ }
+ SessionPoolOptions.Builder builder = SessionPoolOptions.newBuilder().setFailOnSessionLeak();
+ if (failOnInvalidatedSession) {
+ builder.setFailIfSessionNotFound();
+ }
+ // This prevents repeated retries for a large number of sessions in the pool.
+ builder.setMinSessions(1);
+ spanner =
+ SpannerOptions.newBuilder()
+ .setProjectId("[PROJECT]")
+ .setChannelProvider(channelProvider)
+ .setSessionPoolOption(builder.build())
+ .setCredentials(NoCredentials.getInstance())
+ .build()
+ .getService();
+ client = spanner.getDatabaseClient(DatabaseId.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"));
+ invalidateSessionPool(client, spanner.getOptions().getSessionPoolOptions().getMinSessions());
}
- spanner =
- SpannerOptions.newBuilder()
- .setProjectId("[PROJECT]")
- .setChannelProvider(channelProvider)
- .setSessionPoolOption(builder.build())
- .setCredentials(NoCredentials.getInstance())
- .build()
- .getService();
- client = spanner.getDatabaseClient(DatabaseId.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"));
- }
-
- @After
- public void tearDown() {
- spanner.close();
- }
-
- private static void invalidateSessionPool() throws InterruptedException {
- invalidateSessionPool(client, spanner.getOptions().getSessionPoolOptions().getMinSessions());
}
private static void invalidateSessionPool(DatabaseClient client, int minSessions)
@@ -242,7 +238,7 @@ private static void invalidateSessionPool(DatabaseClient client, int minSessions
if (watch.elapsed(TimeUnit.SECONDS) > 5L) {
fail(String.format("Failed to create MinSessions=%d", minSessions));
}
- Thread.sleep(5L);
+ Thread.sleep(1L);
}
ListSessionsPagedResponse response =
@@ -252,333 +248,226 @@ private static void invalidateSessionPool(DatabaseClient client, int minSessions
}
}
+ private T assertThrowsSessionNotFoundIfShouldFail(Supplier supplier) {
+ if (failOnInvalidatedSession) {
+ assertThrows(SessionNotFoundException.class, () -> supplier.get());
+ return null;
+ } else {
+ return supplier.get();
+ }
+ }
+
@Test
public void singleUseSelect() throws InterruptedException {
- invalidateSessionPool();
- try {
- // This call will receive an invalidated session that will be replaced on the first call to
- // rs.next().
- int count = 0;
- try (ReadContext context = client.singleUse()) {
- try (ResultSet rs = context.executeQuery(SELECT1AND2)) {
- while (rs.next()) {
- count++;
- }
- }
+ // This call will receive an invalidated session that will be replaced on the first call to
+ // rs.next().
+ try (ReadContext context = client.singleUse()) {
+ try (ResultSet rs = context.executeQuery(SELECT1AND2)) {
+ assertThrowsSessionNotFoundIfShouldFail(() -> rs.next());
}
- assertThat(count).isEqualTo(2);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
}
}
@Test
public void singleUseSelectAsync() throws Exception {
- invalidateSessionPool();
ApiFuture> list;
try (AsyncResultSet rs = client.singleUse().executeQueryAsync(SELECT1AND2)) {
list = rs.toListAsync(TO_LONG, executor);
- assertThat(list.get()).containsExactly(1L, 2L);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (ExecutionException e) {
- assertThat(e.getCause()).isInstanceOf(SessionNotFoundException.class);
- assertThat(failOnInvalidatedSession).isTrue();
+ assertThrowsSessionNotFoundIfShouldFail(() -> get(list));
}
}
@Test
public void singleUseRead() throws InterruptedException {
- invalidateSessionPool();
- int count = 0;
try (ReadContext context = client.singleUse()) {
try (ResultSet rs = context.read("FOO", KeySet.all(), Collections.singletonList("BAR"))) {
- while (rs.next()) {
- count++;
- }
+ assertThrowsSessionNotFoundIfShouldFail(() -> rs.next());
}
- assertThat(count).isEqualTo(2);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
}
}
@Test
public void singleUseReadUsingIndex() throws InterruptedException {
- invalidateSessionPool();
- int count = 0;
try (ReadContext context = client.singleUse()) {
try (ResultSet rs =
context.readUsingIndex("FOO", "IDX", KeySet.all(), Collections.singletonList("BAR"))) {
- while (rs.next()) {
- count++;
- }
+ assertThrowsSessionNotFoundIfShouldFail(() -> rs.next());
}
- assertThat(count).isEqualTo(2);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
}
}
@Test
public void singleUseReadRow() throws InterruptedException {
- invalidateSessionPool();
try (ReadContext context = client.singleUse()) {
- Struct row = context.readRow("FOO", Key.of(), Collections.singletonList("BAR"));
- assertThat(row.getLong(0)).isEqualTo(1L);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
+ assertThrowsSessionNotFoundIfShouldFail(
+ () -> context.readRow("FOO", Key.of(), Collections.singletonList("BAR")));
}
}
@Test
public void singleUseReadRowUsingIndex() throws InterruptedException {
- invalidateSessionPool();
try (ReadContext context = client.singleUse()) {
- Struct row =
- context.readRowUsingIndex("FOO", "IDX", Key.of(), Collections.singletonList("BAR"));
- assertThat(row.getLong(0)).isEqualTo(1L);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
+ assertThrowsSessionNotFoundIfShouldFail(
+ () ->
+ context.readRowUsingIndex("FOO", "IDX", Key.of(), Collections.singletonList("BAR")));
}
}
@Test
public void singleUseReadOnlyTransactionSelect() throws InterruptedException {
- invalidateSessionPool();
- int count = 0;
try (ReadContext context = client.singleUseReadOnlyTransaction()) {
try (ResultSet rs = context.executeQuery(SELECT1AND2)) {
- while (rs.next()) {
- count++;
- }
+ assertThrowsSessionNotFoundIfShouldFail(() -> rs.next());
}
- assertThat(count).isEqualTo(2);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
}
}
@Test
public void singleUseReadOnlyTransactionRead() throws InterruptedException {
- invalidateSessionPool();
- int count = 0;
try (ReadContext context = client.singleUseReadOnlyTransaction()) {
try (ResultSet rs = context.read("FOO", KeySet.all(), Collections.singletonList("BAR"))) {
- while (rs.next()) {
- count++;
- }
+ assertThrowsSessionNotFoundIfShouldFail(() -> rs.next());
}
- assertThat(count).isEqualTo(2);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
}
}
@Test
public void singlUseReadOnlyTransactionReadUsingIndex() throws InterruptedException {
- invalidateSessionPool();
- int count = 0;
try (ReadContext context = client.singleUseReadOnlyTransaction()) {
try (ResultSet rs =
context.readUsingIndex("FOO", "IDX", KeySet.all(), Collections.singletonList("BAR"))) {
- while (rs.next()) {
- count++;
- }
+ assertThrowsSessionNotFoundIfShouldFail(() -> rs.next());
}
- assertThat(count).isEqualTo(2);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
}
}
@Test
public void singleUseReadOnlyTransactionReadRow() throws InterruptedException {
- invalidateSessionPool();
try (ReadContext context = client.singleUseReadOnlyTransaction()) {
- Struct row = context.readRow("FOO", Key.of(), Collections.singletonList("BAR"));
- assertThat(row.getLong(0)).isEqualTo(1L);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
+ assertThrowsSessionNotFoundIfShouldFail(
+ () -> context.readRow("FOO", Key.of(), Collections.singletonList("BAR")));
}
}
@Test
public void singleUseReadOnlyTransactionReadRowUsingIndex() throws InterruptedException {
- invalidateSessionPool();
try (ReadContext context = client.singleUseReadOnlyTransaction()) {
- Struct row =
- context.readRowUsingIndex("FOO", "IDX", Key.of(), Collections.singletonList("BAR"));
- assertThat(row.getLong(0)).isEqualTo(1L);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
+ assertThrowsSessionNotFoundIfShouldFail(
+ () ->
+ context.readRowUsingIndex("FOO", "IDX", Key.of(), Collections.singletonList("BAR")));
}
}
@Test
public void readOnlyTransactionSelect() throws InterruptedException {
- invalidateSessionPool();
- int count = 0;
try (ReadContext context = client.readOnlyTransaction()) {
try (ResultSet rs = context.executeQuery(SELECT1AND2)) {
- while (rs.next()) {
- count++;
- }
+ assertThrowsSessionNotFoundIfShouldFail(() -> rs.next());
}
- assertThat(count).isEqualTo(2);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
}
}
@Test
public void readOnlyTransactionRead() throws InterruptedException {
- invalidateSessionPool();
- int count = 0;
try (ReadContext context = client.readOnlyTransaction()) {
try (ResultSet rs = context.read("FOO", KeySet.all(), Collections.singletonList("BAR"))) {
- while (rs.next()) {
- count++;
- }
+ assertThrowsSessionNotFoundIfShouldFail(() -> rs.next());
}
- assertThat(count).isEqualTo(2);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
}
}
@Test
public void readOnlyTransactionReadUsingIndex() throws InterruptedException {
- invalidateSessionPool();
- int count = 0;
try (ReadContext context = client.readOnlyTransaction()) {
try (ResultSet rs =
context.readUsingIndex("FOO", "IDX", KeySet.all(), Collections.singletonList("BAR"))) {
- while (rs.next()) {
- count++;
- }
+ assertThrowsSessionNotFoundIfShouldFail(() -> rs.next());
}
- assertThat(count).isEqualTo(2);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
}
}
@Test
public void readOnlyTransactionReadRow() throws InterruptedException {
- invalidateSessionPool();
try (ReadContext context = client.readOnlyTransaction()) {
- Struct row = context.readRow("FOO", Key.of(), Collections.singletonList("BAR"));
- assertThat(row.getLong(0)).isEqualTo(1L);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
+ assertThrowsSessionNotFoundIfShouldFail(
+ () -> context.readRow("FOO", Key.of(), Collections.singletonList("BAR")));
}
}
@Test
public void readOnlyTransactionReadRowUsingIndex() throws InterruptedException {
- invalidateSessionPool();
try (ReadContext context = client.readOnlyTransaction()) {
- Struct row =
- context.readRowUsingIndex("FOO", "IDX", Key.of(), Collections.singletonList("BAR"));
- assertThat(row.getLong(0)).isEqualTo(1L);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
+ assertThrowsSessionNotFoundIfShouldFail(
+ () ->
+ context.readRowUsingIndex("FOO", "IDX", Key.of(), Collections.singletonList("BAR")));
}
}
- @Test(expected = SessionNotFoundException.class)
+ @Test
public void readOnlyTransactionSelectNonRecoverable() throws InterruptedException {
- int count = 0;
try (ReadContext context = client.readOnlyTransaction()) {
try (ResultSet rs = context.executeQuery(SELECT1AND2)) {
- while (rs.next()) {
- count++;
- }
+ assertThrowsSessionNotFoundIfShouldFail(() -> rs.next());
}
- assertThat(count).isEqualTo(2);
// Invalidate the session pool while in a transaction. This is not recoverable.
- invalidateSessionPool();
+ invalidateSessionPool(client, spanner.getOptions().getSessionPoolOptions().getMinSessions());
try (ResultSet rs = context.executeQuery(SELECT1AND2)) {
- while (rs.next()) {
- count++;
- }
+ assertThrows(SessionNotFoundException.class, () -> rs.next());
}
}
}
- @Test(expected = SessionNotFoundException.class)
+ @Test
public void readOnlyTransactionReadNonRecoverable() throws InterruptedException {
- int count = 0;
try (ReadContext context = client.readOnlyTransaction()) {
try (ResultSet rs = context.read("FOO", KeySet.all(), Collections.singletonList("BAR"))) {
- while (rs.next()) {
- count++;
- }
+ assertThrowsSessionNotFoundIfShouldFail(() -> rs.next());
}
- assertThat(count).isEqualTo(2);
- invalidateSessionPool();
+ invalidateSessionPool(client, spanner.getOptions().getSessionPoolOptions().getMinSessions());
try (ResultSet rs = context.read("FOO", KeySet.all(), Collections.singletonList("BAR"))) {
- while (rs.next()) {
- count++;
- }
+ assertThrows(SessionNotFoundException.class, () -> rs.next());
}
}
}
- @Test(expected = SessionNotFoundException.class)
+ @Test
public void readOnlyTransactionReadUsingIndexNonRecoverable() throws InterruptedException {
- int count = 0;
try (ReadContext context = client.readOnlyTransaction()) {
try (ResultSet rs =
context.readUsingIndex("FOO", "IDX", KeySet.all(), Collections.singletonList("BAR"))) {
- while (rs.next()) {
- count++;
- }
+ assertThrowsSessionNotFoundIfShouldFail(() -> rs.next());
}
- assertThat(count).isEqualTo(2);
- invalidateSessionPool();
+ invalidateSessionPool(client, spanner.getOptions().getSessionPoolOptions().getMinSessions());
try (ResultSet rs =
context.readUsingIndex("FOO", "IDX", KeySet.all(), Collections.singletonList("BAR"))) {
- while (rs.next()) {
- count++;
- }
+ assertThrows(SessionNotFoundException.class, () -> rs.next());
}
}
}
- @Test(expected = SessionNotFoundException.class)
+ @Test
public void readOnlyTransactionReadRowNonRecoverable() throws InterruptedException {
try (ReadContext context = client.readOnlyTransaction()) {
- Struct row = context.readRow("FOO", Key.of(), Collections.singletonList("BAR"));
- assertThat(row.getLong(0)).isEqualTo(1L);
- invalidateSessionPool();
- context.readRow("FOO", Key.of(), Collections.singletonList("BAR"));
+ assertThrowsSessionNotFoundIfShouldFail(
+ () -> context.readRow("FOO", Key.of(), Collections.singletonList("BAR")));
+ invalidateSessionPool(client, spanner.getOptions().getSessionPoolOptions().getMinSessions());
+ assertThrows(
+ SessionNotFoundException.class,
+ () -> context.readRow("FOO", Key.of(), Collections.singletonList("BAR")));
}
}
- @Test(expected = SessionNotFoundException.class)
+ @Test
public void readOnlyTransactionReadRowUsingIndexNonRecoverable() throws InterruptedException {
try (ReadContext context = client.readOnlyTransaction()) {
- Struct row =
- context.readRowUsingIndex("FOO", "IDX", Key.of(), Collections.singletonList("BAR"));
- assertThat(row.getLong(0)).isEqualTo(1L);
- invalidateSessionPool();
- context.readRowUsingIndex("FOO", "IDX", Key.of(), Collections.singletonList("BAR"));
+ assertThrowsSessionNotFoundIfShouldFail(
+ () ->
+ context.readRowUsingIndex("FOO", "IDX", Key.of(), Collections.singletonList("BAR")));
+ invalidateSessionPool(client, spanner.getOptions().getSessionPoolOptions().getMinSessions());
+ assertThrows(
+ SessionNotFoundException.class,
+ () ->
+ context.readRowUsingIndex("FOO", "IDX", Key.of(), Collections.singletonList("BAR")));
}
}
@@ -588,581 +477,409 @@ public void readWriteTransactionReadOnlySessionInPool() throws InterruptedExcept
if (failOnInvalidatedSession) {
builder.setFailIfSessionNotFound();
}
- Spanner spanner =
+ try (Spanner spanner =
SpannerOptions.newBuilder()
.setProjectId("[PROJECT]")
.setChannelProvider(channelProvider)
.setSessionPoolOption(builder.build())
.setCredentials(NoCredentials.getInstance())
.build()
- .getService();
- DatabaseClient client =
- spanner.getDatabaseClient(DatabaseId.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"));
- invalidateSessionPool(client, spanner.getOptions().getSessionPoolOptions().getMinSessions());
- try {
+ .getService()) {
+ DatabaseClient client =
+ spanner.getDatabaseClient(DatabaseId.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"));
+ invalidateSessionPool(client, spanner.getOptions().getSessionPoolOptions().getMinSessions());
TransactionRunner runner = client.readWriteTransaction();
- int count =
- runner.run(
- transaction -> {
- int count1 = 0;
- try (ResultSet rs = transaction.executeQuery(SELECT1AND2)) {
- while (rs.next()) {
- count1++;
- }
- }
- return count1;
- });
- assertThat(count).isEqualTo(2);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
+ assertThrowsSessionNotFoundIfShouldFail(
+ () ->
+ runner.run(
+ transaction -> {
+ try (ResultSet rs = transaction.executeQuery(SELECT1AND2)) {
+ while (rs.next()) {}
+ }
+ return null;
+ }));
}
}
@Test
public void readWriteTransactionSelect() throws InterruptedException {
- invalidateSessionPool();
- try {
- TransactionRunner runner = client.readWriteTransaction();
- int count =
- runner.run(
- transaction -> {
- int count1 = 0;
- try (ResultSet rs = transaction.executeQuery(SELECT1AND2)) {
- while (rs.next()) {
- count1++;
+ TransactionRunner runner = client.readWriteTransaction();
+ assertThrowsSessionNotFoundIfShouldFail(
+ () ->
+ runner.run(
+ transaction -> {
+ try (ResultSet rs = transaction.executeQuery(SELECT1AND2)) {
+ while (rs.next()) {}
}
- }
- return count1;
- });
- assertThat(count).isEqualTo(2);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
- }
+ return null;
+ }));
}
@Test
public void readWriteTransactionRead() throws InterruptedException {
- invalidateSessionPool();
- try {
- TransactionRunner runner = client.readWriteTransaction();
- int count =
- runner.run(
- transaction -> {
- int count1 = 0;
- try (ResultSet rs =
- transaction.read("FOO", KeySet.all(), Collections.singletonList("BAR"))) {
- while (rs.next()) {
- count1++;
+ TransactionRunner runner = client.readWriteTransaction();
+ assertThrowsSessionNotFoundIfShouldFail(
+ () ->
+ runner.run(
+ transaction -> {
+ try (ResultSet rs =
+ transaction.read("FOO", KeySet.all(), Collections.singletonList("BAR"))) {
+ while (rs.next()) {}
}
- }
- return count1;
- });
- assertThat(count).isEqualTo(2);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
- }
+ return null;
+ }));
}
@Test
public void readWriteTransactionReadUsingIndex() throws InterruptedException {
- invalidateSessionPool();
- try {
- TransactionRunner runner = client.readWriteTransaction();
- int count =
- runner.run(
- transaction -> {
- int count1 = 0;
- try (ResultSet rs =
- transaction.readUsingIndex(
- "FOO", "IDX", KeySet.all(), Collections.singletonList("BAR"))) {
- while (rs.next()) {
- count1++;
+ TransactionRunner runner = client.readWriteTransaction();
+ assertThrowsSessionNotFoundIfShouldFail(
+ () ->
+ runner.run(
+ transaction -> {
+ try (ResultSet rs =
+ transaction.readUsingIndex(
+ "FOO", "IDX", KeySet.all(), Collections.singletonList("BAR"))) {
+ while (rs.next()) {}
}
- }
- return count1;
- });
- assertThat(count).isEqualTo(2);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
- }
+ return null;
+ }));
}
@Test
public void readWriteTransactionReadRow() throws InterruptedException {
- invalidateSessionPool();
- try {
- TransactionRunner runner = client.readWriteTransaction();
- Struct row =
- runner.run(
- transaction ->
- transaction.readRow("FOO", Key.of(), Collections.singletonList("BAR")));
- assertThat(row.getLong(0)).isEqualTo(1L);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
- }
+ TransactionRunner runner = client.readWriteTransaction();
+ assertThrowsSessionNotFoundIfShouldFail(
+ () ->
+ runner.run(
+ transaction ->
+ transaction.readRow("FOO", Key.of(), Collections.singletonList("BAR"))));
}
@Test
public void readWriteTransactionReadRowUsingIndex() throws InterruptedException {
- invalidateSessionPool();
- try {
- TransactionRunner runner = client.readWriteTransaction();
- Struct row =
- runner.run(
- transaction ->
- transaction.readRowUsingIndex(
- "FOO", "IDX", Key.of(), Collections.singletonList("BAR")));
- assertThat(row.getLong(0)).isEqualTo(1L);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
- }
+ TransactionRunner runner = client.readWriteTransaction();
+ assertThrowsSessionNotFoundIfShouldFail(
+ () ->
+ runner.run(
+ transaction ->
+ transaction.readRowUsingIndex(
+ "FOO", "IDX", Key.of(), Collections.singletonList("BAR"))));
}
@Test
public void readWriteTransactionUpdate() throws InterruptedException {
- invalidateSessionPool();
- try {
- TransactionRunner runner = client.readWriteTransaction();
- long count = runner.run(transaction -> transaction.executeUpdate(UPDATE_STATEMENT));
- assertThat(count).isEqualTo(UPDATE_COUNT);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
- }
+ TransactionRunner runner = client.readWriteTransaction();
+ assertThrowsSessionNotFoundIfShouldFail(
+ () -> runner.run(transaction -> transaction.executeUpdate(UPDATE_STATEMENT)));
}
@Test
public void readWriteTransactionBatchUpdate() throws InterruptedException {
- invalidateSessionPool();
- try {
- TransactionRunner runner = client.readWriteTransaction();
- long[] count =
- runner.run(
- transaction -> transaction.batchUpdate(Collections.singletonList(UPDATE_STATEMENT)));
- assertThat(count.length).isEqualTo(1);
- assertThat(count[0]).isEqualTo(UPDATE_COUNT);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
- }
+ TransactionRunner runner = client.readWriteTransaction();
+ assertThrowsSessionNotFoundIfShouldFail(
+ () ->
+ runner.run(
+ transaction ->
+ transaction.batchUpdate(Collections.singletonList(UPDATE_STATEMENT))));
}
@Test
public void readWriteTransactionBuffer() throws InterruptedException {
- invalidateSessionPool();
- try {
- TransactionRunner runner = client.readWriteTransaction();
- runner.run(
- transaction -> {
- transaction.buffer(Mutation.newInsertBuilder("FOO").set("BAR").to(1L).build());
- return null;
- });
- assertThat(runner.getCommitTimestamp()).isNotNull();
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
- }
+ TransactionRunner runner = client.readWriteTransaction();
+ assertThrowsSessionNotFoundIfShouldFail(
+ () ->
+ runner.run(
+ transaction -> {
+ transaction.buffer(Mutation.newInsertBuilder("FOO").set("BAR").to(1L).build());
+ return null;
+ }));
}
@Test
public void readWriteTransactionSelectInvalidatedDuringTransaction() {
- try {
- TransactionRunner runner = client.readWriteTransaction();
- int attempts =
- runner.run(
- new TransactionCallable() {
- private int attempt = 0;
-
- @Override
- public Integer run(TransactionContext transaction) throws Exception {
- attempt++;
- int count = 0;
+ TransactionRunner runner = client.readWriteTransaction();
+ final AtomicInteger attempt = new AtomicInteger();
+ assertThrowsSessionNotFoundIfShouldFail(
+ () ->
+ runner.run(
+ transaction -> {
+ attempt.incrementAndGet();
try (ResultSet rs = transaction.executeQuery(SELECT1AND2)) {
- while (rs.next()) {
- count++;
- }
+ while (rs.next()) {}
}
- assertThat(count).isEqualTo(2);
- if (attempt == 1) {
- invalidateSessionPool();
+ if (attempt.get() == 1) {
+ invalidateSessionPool(
+ client, spanner.getOptions().getSessionPoolOptions().getMinSessions());
}
try (ResultSet rs = transaction.executeQuery(SELECT1AND2)) {
- while (rs.next()) {
- count++;
- }
+ while (rs.next()) {}
}
- return attempt;
- }
- });
- assertThat(attempts).isGreaterThan(1);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
- }
+ assertThat(attempt.get()).isGreaterThan(1);
+ return null;
+ }));
}
@Test
public void readWriteTransactionReadInvalidatedDuringTransaction() {
- try {
- TransactionRunner runner = client.readWriteTransaction();
- int attempts =
- runner.run(
- new TransactionCallable() {
- private int attempt = 0;
-
- @Override
- public Integer run(TransactionContext transaction) throws Exception {
- attempt++;
- int count = 0;
+ TransactionRunner runner = client.readWriteTransaction();
+ final AtomicInteger attempt = new AtomicInteger();
+ assertThrowsSessionNotFoundIfShouldFail(
+ () ->
+ runner.run(
+ transaction -> {
+ attempt.incrementAndGet();
try (ResultSet rs =
transaction.read("FOO", KeySet.all(), Collections.singletonList("BAR"))) {
- while (rs.next()) {
- count++;
- }
+ while (rs.next()) {}
}
- assertThat(count).isEqualTo(2);
- if (attempt == 1) {
- invalidateSessionPool();
+ if (attempt.get() == 1) {
+ invalidateSessionPool(
+ client, spanner.getOptions().getSessionPoolOptions().getMinSessions());
}
try (ResultSet rs =
transaction.read("FOO", KeySet.all(), Collections.singletonList("BAR"))) {
- while (rs.next()) {
- count++;
- }
+ while (rs.next()) {}
}
- return attempt;
- }
- });
- assertThat(attempts).isGreaterThan(1);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
- }
+ assertThat(attempt.get()).isGreaterThan(1);
+ return null;
+ }));
}
@Test
public void readWriteTransactionReadUsingIndexInvalidatedDuringTransaction() {
- try {
- TransactionRunner runner = client.readWriteTransaction();
- int attempts =
- runner.run(
- new TransactionCallable() {
- private int attempt = 0;
-
- @Override
- public Integer run(TransactionContext transaction) throws Exception {
- attempt++;
- int count = 0;
+ TransactionRunner runner = client.readWriteTransaction();
+ final AtomicInteger attempt = new AtomicInteger();
+ assertThrowsSessionNotFoundIfShouldFail(
+ () ->
+ runner.run(
+ transaction -> {
+ attempt.incrementAndGet();
try (ResultSet rs =
transaction.readUsingIndex(
"FOO", "IDX", KeySet.all(), Collections.singletonList("BAR"))) {
- while (rs.next()) {
- count++;
- }
+ while (rs.next()) {}
}
- assertThat(count).isEqualTo(2);
- if (attempt == 1) {
- invalidateSessionPool();
+ if (attempt.get() == 1) {
+ invalidateSessionPool(
+ client, spanner.getOptions().getSessionPoolOptions().getMinSessions());
}
try (ResultSet rs =
transaction.readUsingIndex(
"FOO", "IDX", KeySet.all(), Collections.singletonList("BAR"))) {
- while (rs.next()) {
- count++;
- }
+ while (rs.next()) {}
}
- return attempt;
- }
- });
- assertThat(attempts).isGreaterThan(1);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
- }
+ assertThat(attempt.get()).isGreaterThan(1);
+ return null;
+ }));
}
@Test
public void readWriteTransactionReadRowInvalidatedDuringTransaction() {
- try {
- TransactionRunner runner = client.readWriteTransaction();
- int attempts =
- runner.run(
- new TransactionCallable() {
- private int attempt = 0;
-
- @Override
- public Integer run(TransactionContext transaction) throws Exception {
- attempt++;
+ TransactionRunner runner = client.readWriteTransaction();
+ final AtomicInteger attempt = new AtomicInteger();
+ assertThrowsSessionNotFoundIfShouldFail(
+ () ->
+ runner.run(
+ transaction -> {
+ attempt.incrementAndGet();
Struct row =
transaction.readRow("FOO", Key.of(), Collections.singletonList("BAR"));
assertThat(row.getLong(0)).isEqualTo(1L);
- if (attempt == 1) {
- invalidateSessionPool();
+ if (attempt.get() == 1) {
+ invalidateSessionPool(
+ client, spanner.getOptions().getSessionPoolOptions().getMinSessions());
}
transaction.readRow("FOO", Key.of(), Collections.singletonList("BAR"));
- return attempt;
- }
- });
- assertThat(attempts).isGreaterThan(1);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
- }
+ assertThat(attempt.get()).isGreaterThan(1);
+ return null;
+ }));
}
@Test
public void readWriteTransactionReadRowUsingIndexInvalidatedDuringTransaction() {
- try {
- TransactionRunner runner = client.readWriteTransaction();
- int attempts =
- runner.run(
- new TransactionCallable() {
- private int attempt = 0;
-
- @Override
- public Integer run(TransactionContext transaction) throws Exception {
- attempt++;
+ TransactionRunner runner = client.readWriteTransaction();
+ final AtomicInteger attempt = new AtomicInteger();
+ assertThrowsSessionNotFoundIfShouldFail(
+ () ->
+ runner.run(
+ transaction -> {
+ attempt.incrementAndGet();
Struct row =
transaction.readRowUsingIndex(
"FOO", "IDX", Key.of(), Collections.singletonList("BAR"));
assertThat(row.getLong(0)).isEqualTo(1L);
- if (attempt == 1) {
- invalidateSessionPool();
+ if (attempt.get() == 1) {
+ invalidateSessionPool(
+ client, spanner.getOptions().getSessionPoolOptions().getMinSessions());
}
transaction.readRowUsingIndex(
"FOO", "IDX", Key.of(), Collections.singletonList("BAR"));
- return attempt;
- }
- });
- assertThat(attempts).isGreaterThan(1);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
- }
+ assertThat(attempt.get()).isGreaterThan(1);
+ return null;
+ }));
}
- /**
- * Test with one read-only session in the pool that is invalidated. The session pool will try to
- * prepare this session for read/write, which will fail with a {@link SessionNotFoundException}.
- * That again will trigger the creation of a new session. This will always succeed.
- */
@SuppressWarnings("resource")
@Test
public void transactionManagerReadOnlySessionInPool() throws InterruptedException {
- SessionPoolOptions.Builder builder = SessionPoolOptions.newBuilder();
- if (failOnInvalidatedSession) {
- builder.setFailIfSessionNotFound();
- }
- Spanner spanner =
- SpannerOptions.newBuilder()
- .setProjectId("[PROJECT]")
- .setChannelProvider(channelProvider)
- .setSessionPoolOption(builder.build())
- .setCredentials(NoCredentials.getInstance())
- .build()
- .getService();
- DatabaseClient client =
- spanner.getDatabaseClient(DatabaseId.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"));
- invalidateSessionPool(client, spanner.getOptions().getSessionPoolOptions().getMinSessions());
- int count = 0;
try (TransactionManager manager = client.transactionManager()) {
TransactionContext transaction = manager.begin();
while (true) {
try {
try (ResultSet rs = transaction.executeQuery(SELECT1AND2)) {
- while (rs.next()) {
- count++;
- }
+ assertThrowsSessionNotFoundIfShouldFail(() -> rs.next());
}
manager.commit();
break;
} catch (AbortedException e) {
- Thread.sleep(e.getRetryDelayInMillis());
- transaction = manager.resetForRetry();
+ transaction = assertThrowsSessionNotFoundIfShouldFail(() -> manager.resetForRetry());
+ if (transaction == null) {
+ break;
+ }
}
}
- assertThat(count).isEqualTo(2);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
}
}
@SuppressWarnings("resource")
@Test
public void transactionManagerSelect() throws InterruptedException {
- invalidateSessionPool();
try (TransactionManager manager = client.transactionManager()) {
- int count = 0;
TransactionContext transaction = manager.begin();
while (true) {
try {
try (ResultSet rs = transaction.executeQuery(SELECT1AND2)) {
- while (rs.next()) {
- count++;
- }
+ assertThrowsSessionNotFoundIfShouldFail(() -> rs.next());
}
manager.commit();
break;
} catch (AbortedException e) {
- Thread.sleep(e.getRetryDelayInMillis());
- transaction = manager.resetForRetry();
+ transaction = assertThrowsSessionNotFoundIfShouldFail(() -> manager.resetForRetry());
+ if (transaction == null) {
+ break;
+ }
}
}
- assertThat(count).isEqualTo(2);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
}
}
@SuppressWarnings("resource")
@Test
public void transactionManagerRead() throws InterruptedException {
- invalidateSessionPool();
try (TransactionManager manager = client.transactionManager()) {
- int count = 0;
TransactionContext transaction = manager.begin();
while (true) {
try {
try (ResultSet rs =
transaction.read("FOO", KeySet.all(), Collections.singletonList("BAR"))) {
- while (rs.next()) {
- count++;
- }
+ assertThrowsSessionNotFoundIfShouldFail(() -> rs.next());
}
manager.commit();
break;
} catch (AbortedException e) {
- Thread.sleep(e.getRetryDelayInMillis());
- transaction = manager.resetForRetry();
+ transaction = assertThrowsSessionNotFoundIfShouldFail(() -> manager.resetForRetry());
+ if (transaction == null) {
+ break;
+ }
}
}
- assertThat(count).isEqualTo(2);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
}
}
@SuppressWarnings("resource")
@Test
public void transactionManagerReadUsingIndex() throws InterruptedException {
- invalidateSessionPool();
try (TransactionManager manager = client.transactionManager()) {
- int count = 0;
TransactionContext transaction = manager.begin();
while (true) {
try {
try (ResultSet rs =
transaction.readUsingIndex(
"FOO", "IDX", KeySet.all(), Collections.singletonList("BAR"))) {
- while (rs.next()) {
- count++;
- }
+ assertThrowsSessionNotFoundIfShouldFail(() -> rs.next());
}
manager.commit();
break;
} catch (AbortedException e) {
- Thread.sleep(e.getRetryDelayInMillis());
- transaction = manager.resetForRetry();
+ transaction = assertThrowsSessionNotFoundIfShouldFail(() -> manager.resetForRetry());
+ if (transaction == null) {
+ break;
+ }
}
}
- assertThat(count).isEqualTo(2);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
}
}
- @SuppressWarnings("resource")
@Test
public void transactionManagerReadRow() throws InterruptedException {
- invalidateSessionPool();
try (TransactionManager manager = client.transactionManager()) {
- Struct row;
TransactionContext transaction = manager.begin();
while (true) {
try {
- row = transaction.readRow("FOO", Key.of(), Collections.singletonList("BAR"));
+ TransactionContext context = transaction;
+ assertThrowsSessionNotFoundIfShouldFail(
+ () -> context.readRow("FOO", Key.of(), Collections.singletonList("BAR")));
manager.commit();
break;
} catch (AbortedException e) {
- Thread.sleep(e.getRetryDelayInMillis());
- transaction = manager.resetForRetry();
+ transaction = assertThrowsSessionNotFoundIfShouldFail(() -> manager.resetForRetry());
+ if (transaction == null) {
+ break;
+ }
}
}
- assertThat(row.getLong(0)).isEqualTo(1L);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
}
}
- @SuppressWarnings("resource")
@Test
public void transactionManagerReadRowUsingIndex() throws InterruptedException {
- invalidateSessionPool();
try (TransactionManager manager = client.transactionManager()) {
- Struct row;
TransactionContext transaction = manager.begin();
while (true) {
try {
- row =
- transaction.readRowUsingIndex(
- "FOO", "IDX", Key.of(), Collections.singletonList("BAR"));
+ TransactionContext context = transaction;
+ assertThrowsSessionNotFoundIfShouldFail(
+ () ->
+ context.readRowUsingIndex(
+ "FOO", "IDX", Key.of(), Collections.singletonList("BAR")));
manager.commit();
break;
} catch (AbortedException e) {
- Thread.sleep(e.getRetryDelayInMillis());
- transaction = manager.resetForRetry();
+ transaction = assertThrowsSessionNotFoundIfShouldFail(() -> manager.resetForRetry());
+ if (transaction == null) {
+ break;
+ }
}
}
- assertThat(row.getLong(0)).isEqualTo(1L);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
}
}
- @SuppressWarnings("resource")
@Test
public void transactionManagerUpdate() throws InterruptedException {
- invalidateSessionPool();
try (TransactionManager manager = client.transactionManager(Options.commitStats())) {
- long count;
TransactionContext transaction = manager.begin();
while (true) {
try {
- count = transaction.executeUpdate(UPDATE_STATEMENT);
+ TransactionContext context = transaction;
+ assertThrowsSessionNotFoundIfShouldFail(() -> context.executeUpdate(UPDATE_STATEMENT));
manager.commit();
break;
} catch (AbortedException e) {
- Thread.sleep(e.getRetryDelayInMillis());
- transaction = manager.resetForRetry();
+ transaction = assertThrowsSessionNotFoundIfShouldFail(() -> manager.resetForRetry());
+ if (transaction == null) {
+ break;
+ }
}
}
- assertEquals(UPDATE_COUNT, count);
- assertNotNull(manager.getCommitResponse().getCommitStats());
- assertFalse(failOnInvalidatedSession);
- } catch (SessionNotFoundException e) {
- assertTrue(failOnInvalidatedSession);
}
}
- @SuppressWarnings("resource")
@Test
public void transactionManagerAborted_thenSessionNotFoundOnBeginTransaction()
throws InterruptedException {
int attempt = 0;
try (TransactionManager manager = client.transactionManager()) {
- long count;
TransactionContext transaction = manager.begin();
while (true) {
try {
@@ -1171,55 +888,50 @@ public void transactionManagerAborted_thenSessionNotFoundOnBeginTransaction()
mockSpanner.abortNextStatement();
}
if (attempt == 2) {
- invalidateSessionPool();
+ invalidateSessionPool(
+ client, spanner.getOptions().getSessionPoolOptions().getMinSessions());
}
- count = transaction.executeUpdate(UPDATE_STATEMENT);
+ TransactionContext context = transaction;
+ assertThrowsSessionNotFoundIfShouldFail(() -> context.executeUpdate(UPDATE_STATEMENT));
manager.commit();
+ // The actual number of attempts depends on when the transaction manager will actually get
+ // a valid session, as we invalidate the entire session pool.
+ assertThat(attempt).isAtLeast(3);
break;
} catch (AbortedException e) {
- Thread.sleep(e.getRetryDelayInMillis());
- transaction = manager.resetForRetry();
+ transaction = assertThrowsSessionNotFoundIfShouldFail(() -> manager.resetForRetry());
+ if (transaction == null) {
+ break;
+ }
}
}
- assertThat(count).isEqualTo(UPDATE_COUNT);
- assertThat(failOnInvalidatedSession).isFalse();
- // The actual number of attempts depends on when the transaction manager will actually get a
- // valid session, as we invalidate the entire session pool.
- assertThat(attempt).isAtLeast(3);
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
}
}
- @SuppressWarnings("resource")
@Test
public void transactionManagerBatchUpdate() throws InterruptedException {
- invalidateSessionPool();
try (TransactionManager manager = client.transactionManager()) {
- long[] count;
TransactionContext transaction = manager.begin();
while (true) {
try {
- count = transaction.batchUpdate(Collections.singletonList(UPDATE_STATEMENT));
+ TransactionContext context = transaction;
+ assertThrowsSessionNotFoundIfShouldFail(
+ () -> context.batchUpdate(Collections.singletonList(UPDATE_STATEMENT)));
manager.commit();
break;
} catch (AbortedException e) {
- Thread.sleep(e.getRetryDelayInMillis());
- transaction = manager.resetForRetry();
+ transaction = assertThrowsSessionNotFoundIfShouldFail(() -> manager.resetForRetry());
+ if (transaction == null) {
+ break;
+ }
}
}
- assertThat(count.length).isEqualTo(1);
- assertThat(count[0]).isEqualTo(UPDATE_COUNT);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
}
}
@SuppressWarnings("resource")
@Test
public void transactionManagerBuffer() throws InterruptedException {
- invalidateSessionPool();
try (TransactionManager manager = client.transactionManager()) {
TransactionContext transaction = manager.begin();
while (true) {
@@ -1228,8 +940,10 @@ public void transactionManagerBuffer() throws InterruptedException {
manager.commit();
break;
} catch (AbortedException e) {
- Thread.sleep(e.getRetryDelayInMillis());
- transaction = manager.resetForRetry();
+ transaction = assertThrowsSessionNotFoundIfShouldFail(() -> manager.resetForRetry());
+ if (transaction == null) {
+ break;
+ }
}
}
assertThat(manager.getCommitTimestamp()).isNotNull();
@@ -1242,78 +956,93 @@ public void transactionManagerBuffer() throws InterruptedException {
@SuppressWarnings("resource")
@Test
public void transactionManagerSelectInvalidatedDuringTransaction() throws InterruptedException {
- try (TransactionManager manager = client.transactionManager()) {
- int attempts = 0;
- TransactionContext transaction = manager.begin();
- while (true) {
- attempts++;
- int count = 0;
- try {
- try (ResultSet rs = transaction.executeQuery(SELECT1AND2)) {
- while (rs.next()) {
- count++;
+ SessionPoolOptions.Builder builder = SessionPoolOptions.newBuilder();
+ if (failOnInvalidatedSession) {
+ builder.setFailIfSessionNotFound();
+ }
+ try (Spanner spanner =
+ SpannerOptions.newBuilder()
+ .setProjectId("[PROJECT]")
+ .setChannelProvider(channelProvider)
+ .setSessionPoolOption(builder.build())
+ .setCredentials(NoCredentials.getInstance())
+ .build()
+ .getService()) {
+ DatabaseClient client =
+ spanner.getDatabaseClient(DatabaseId.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"));
+ try (TransactionManager manager = client.transactionManager()) {
+ int attempts = 0;
+ TransactionContext transaction = manager.begin();
+ while (true) {
+ attempts++;
+ try {
+ try (ResultSet rs = transaction.executeQuery(SELECT1AND2)) {
+ while (rs.next()) {}
}
- }
- assertThat(count).isEqualTo(2);
- if (attempts == 1) {
- invalidateSessionPool();
- }
- try (ResultSet rs = transaction.executeQuery(SELECT1AND2)) {
- while (rs.next()) {
- count++;
+ if (attempts == 1) {
+ invalidateSessionPool(
+ client, spanner.getOptions().getSessionPoolOptions().getMinSessions());
+ }
+ try (ResultSet rs = transaction.executeQuery(SELECT1AND2)) {
+ if (assertThrowsSessionNotFoundIfShouldFail(() -> rs.next()) == null) {
+ break;
+ }
}
+ manager.commit();
+ assertThat(attempts).isGreaterThan(1);
+ break;
+ } catch (AbortedException e) {
+ transaction = assertThrowsSessionNotFoundIfShouldFail(() -> manager.resetForRetry());
}
- manager.commit();
- break;
- } catch (AbortedException e) {
- Thread.sleep(e.getRetryDelayInMillis());
- transaction = manager.resetForRetry();
}
}
- assertThat(attempts).isGreaterThan(1);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
}
}
@SuppressWarnings("resource")
@Test
public void transactionManagerReadInvalidatedDuringTransaction() throws InterruptedException {
- try (TransactionManager manager = client.transactionManager()) {
- int attempts = 0;
- TransactionContext transaction = manager.begin();
- while (true) {
- attempts++;
- int count = 0;
- try {
- try (ResultSet rs =
- transaction.read("FOO", KeySet.all(), Collections.singletonList("BAR"))) {
- while (rs.next()) {
- count++;
+ SessionPoolOptions.Builder builder = SessionPoolOptions.newBuilder();
+ if (failOnInvalidatedSession) {
+ builder.setFailIfSessionNotFound();
+ }
+ try (Spanner spanner =
+ SpannerOptions.newBuilder()
+ .setProjectId("[PROJECT]")
+ .setChannelProvider(channelProvider)
+ .setSessionPoolOption(builder.build())
+ .setCredentials(NoCredentials.getInstance())
+ .build()
+ .getService()) {
+ DatabaseClient client =
+ spanner.getDatabaseClient(DatabaseId.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"));
+ try (TransactionManager manager = client.transactionManager()) {
+ int attempts = 0;
+ TransactionContext transaction = manager.begin();
+ while (true) {
+ attempts++;
+ try {
+ try (ResultSet rs =
+ transaction.read("FOO", KeySet.all(), Collections.singletonList("BAR"))) {
+ while (rs.next()) {}
}
- }
- assertThat(count).isEqualTo(2);
- if (attempts == 1) {
- invalidateSessionPool();
- }
- try (ResultSet rs =
- transaction.read("FOO", KeySet.all(), Collections.singletonList("BAR"))) {
- while (rs.next()) {
- count++;
+ if (attempts == 1) {
+ invalidateSessionPool(
+ client, spanner.getOptions().getSessionPoolOptions().getMinSessions());
+ }
+ try (ResultSet rs =
+ transaction.read("FOO", KeySet.all(), Collections.singletonList("BAR"))) {
+ if (assertThrowsSessionNotFoundIfShouldFail(() -> rs.next()) == null) {
+ break;
+ }
}
+ manager.commit();
+ break;
+ } catch (AbortedException e) {
+ transaction = manager.resetForRetry();
}
- manager.commit();
- break;
- } catch (AbortedException e) {
- Thread.sleep(e.getRetryDelayInMillis());
- transaction = manager.resetForRetry();
}
}
- assertThat(attempts).isGreaterThan(1);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
}
}
@@ -1321,71 +1050,94 @@ public void transactionManagerReadInvalidatedDuringTransaction() throws Interrup
@Test
public void transactionManagerReadUsingIndexInvalidatedDuringTransaction()
throws InterruptedException {
- try (TransactionManager manager = client.transactionManager()) {
- int attempts = 0;
- TransactionContext transaction = manager.begin();
- while (true) {
- attempts++;
- int count = 0;
- try {
- try (ResultSet rs =
- transaction.readUsingIndex(
- "FOO", "IDX", KeySet.all(), Collections.singletonList("BAR"))) {
- while (rs.next()) {
- count++;
+ SessionPoolOptions.Builder builder = SessionPoolOptions.newBuilder();
+ if (failOnInvalidatedSession) {
+ builder.setFailIfSessionNotFound();
+ }
+ try (Spanner spanner =
+ SpannerOptions.newBuilder()
+ .setProjectId("[PROJECT]")
+ .setChannelProvider(channelProvider)
+ .setSessionPoolOption(builder.build())
+ .setCredentials(NoCredentials.getInstance())
+ .build()
+ .getService()) {
+ DatabaseClient client =
+ spanner.getDatabaseClient(DatabaseId.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"));
+ try (TransactionManager manager = client.transactionManager()) {
+ int attempts = 0;
+ TransactionContext transaction = manager.begin();
+ while (true) {
+ attempts++;
+ try {
+ try (ResultSet rs =
+ transaction.readUsingIndex(
+ "FOO", "IDX", KeySet.all(), Collections.singletonList("BAR"))) {
+ while (rs.next()) {}
}
- }
- assertThat(count).isEqualTo(2);
- if (attempts == 1) {
- invalidateSessionPool();
- }
- try (ResultSet rs =
- transaction.readUsingIndex(
- "FOO", "IDX", KeySet.all(), Collections.singletonList("BAR"))) {
- while (rs.next()) {
- count++;
+ if (attempts == 1) {
+ invalidateSessionPool(
+ client, spanner.getOptions().getSessionPoolOptions().getMinSessions());
+ }
+ try (ResultSet rs =
+ transaction.readUsingIndex(
+ "FOO", "IDX", KeySet.all(), Collections.singletonList("BAR"))) {
+ if (assertThrowsSessionNotFoundIfShouldFail(() -> rs.next()) == null) {
+ break;
+ }
}
+ manager.commit();
+ break;
+ } catch (AbortedException e) {
+ transaction = manager.resetForRetry();
}
- manager.commit();
- break;
- } catch (AbortedException e) {
- Thread.sleep(e.getRetryDelayInMillis());
- transaction = manager.resetForRetry();
}
}
- assertThat(attempts).isGreaterThan(1);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
}
}
@SuppressWarnings("resource")
@Test
public void transactionManagerReadRowInvalidatedDuringTransaction() throws InterruptedException {
- try (TransactionManager manager = client.transactionManager()) {
- int attempts = 0;
- TransactionContext transaction = manager.begin();
- while (true) {
- attempts++;
- try {
- Struct row = transaction.readRow("FOO", Key.of(), Collections.singletonList("BAR"));
- assertThat(row.getLong(0)).isEqualTo(1L);
- if (attempts == 1) {
- invalidateSessionPool();
+ SessionPoolOptions.Builder builder = SessionPoolOptions.newBuilder();
+ if (failOnInvalidatedSession) {
+ builder.setFailIfSessionNotFound();
+ }
+ try (Spanner spanner =
+ SpannerOptions.newBuilder()
+ .setProjectId("[PROJECT]")
+ .setChannelProvider(channelProvider)
+ .setSessionPoolOption(builder.build())
+ .setCredentials(NoCredentials.getInstance())
+ .build()
+ .getService()) {
+ DatabaseClient client =
+ spanner.getDatabaseClient(DatabaseId.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"));
+ try (TransactionManager manager = client.transactionManager()) {
+ int attempts = 0;
+ TransactionContext transaction = manager.begin();
+ while (true) {
+ attempts++;
+ try {
+ Struct row = transaction.readRow("FOO", Key.of(), Collections.singletonList("BAR"));
+ assertThat(row.getLong(0)).isEqualTo(1L);
+ if (attempts == 1) {
+ invalidateSessionPool(
+ client, spanner.getOptions().getSessionPoolOptions().getMinSessions());
+ }
+ TransactionContext context = transaction;
+ if (assertThrowsSessionNotFoundIfShouldFail(
+ () -> context.readRow("FOO", Key.of(), Collections.singletonList("BAR")))
+ == null) {
+ break;
+ }
+ manager.commit();
+ break;
+ } catch (AbortedException e) {
+ transaction = manager.resetForRetry();
}
- transaction.readRow("FOO", Key.of(), Collections.singletonList("BAR"));
- manager.commit();
- break;
- } catch (AbortedException e) {
- Thread.sleep(e.getRetryDelayInMillis());
- transaction = manager.resetForRetry();
}
}
- assertThat(attempts).isGreaterThan(1);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
}
}
@@ -1393,69 +1145,70 @@ public void transactionManagerReadRowInvalidatedDuringTransaction() throws Inter
@Test
public void transactionManagerReadRowUsingIndexInvalidatedDuringTransaction()
throws InterruptedException {
- try (TransactionManager manager = client.transactionManager()) {
- int attempts = 0;
- TransactionContext transaction = manager.begin();
- while (true) {
- attempts++;
- try {
- Struct row =
- transaction.readRowUsingIndex(
- "FOO", "IDX", Key.of(), Collections.singletonList("BAR"));
- assertThat(row.getLong(0)).isEqualTo(1L);
- if (attempts == 1) {
- invalidateSessionPool();
+ SessionPoolOptions.Builder builder = SessionPoolOptions.newBuilder();
+ if (failOnInvalidatedSession) {
+ builder.setFailIfSessionNotFound();
+ }
+ try (Spanner spanner =
+ SpannerOptions.newBuilder()
+ .setProjectId("[PROJECT]")
+ .setChannelProvider(channelProvider)
+ .setSessionPoolOption(builder.build())
+ .setCredentials(NoCredentials.getInstance())
+ .build()
+ .getService()) {
+ DatabaseClient client =
+ spanner.getDatabaseClient(DatabaseId.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"));
+ try (TransactionManager manager = client.transactionManager()) {
+ int attempts = 0;
+ TransactionContext transaction = manager.begin();
+ while (true) {
+ attempts++;
+ try {
+ Struct row =
+ transaction.readRowUsingIndex(
+ "FOO", "IDX", Key.of(), Collections.singletonList("BAR"));
+ assertThat(row.getLong(0)).isEqualTo(1L);
+ if (attempts == 1) {
+ invalidateSessionPool(
+ client, spanner.getOptions().getSessionPoolOptions().getMinSessions());
+ }
+ TransactionContext context = transaction;
+ if (assertThrowsSessionNotFoundIfShouldFail(
+ () ->
+ context.readRowUsingIndex(
+ "FOO", "IDX", Key.of(), Collections.singletonList("BAR")))
+ == null) {
+ break;
+ }
+ manager.commit();
+ break;
+ } catch (AbortedException e) {
+ transaction = manager.resetForRetry();
}
- transaction.readRowUsingIndex("FOO", "IDX", Key.of(), Collections.singletonList("BAR"));
- manager.commit();
- break;
- } catch (AbortedException e) {
- Thread.sleep(e.getRetryDelayInMillis());
- transaction = manager.resetForRetry();
}
}
- assertThat(attempts).isGreaterThan(1);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
}
}
@Test
public void partitionedDml() throws InterruptedException {
- invalidateSessionPool();
- try {
- assertThat(client.executePartitionedUpdate(UPDATE_STATEMENT)).isEqualTo(UPDATE_COUNT);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
- }
+ assertThrowsSessionNotFoundIfShouldFail(
+ () -> client.executePartitionedUpdate(UPDATE_STATEMENT));
}
@Test
public void write() throws InterruptedException {
- invalidateSessionPool();
- try {
- Timestamp timestamp =
- client.write(Collections.singletonList(Mutation.delete("FOO", KeySet.all())));
- assertThat(timestamp).isNotNull();
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
- }
+ assertThrowsSessionNotFoundIfShouldFail(
+ () -> client.write(Collections.singletonList(Mutation.delete("FOO", KeySet.all()))));
}
@Test
public void writeAtLeastOnce() throws InterruptedException {
- invalidateSessionPool();
- try {
- Timestamp timestamp =
- client.writeAtLeastOnce(Collections.singletonList(Mutation.delete("FOO", KeySet.all())));
- assertThat(timestamp).isNotNull();
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
- }
+ assertThrowsSessionNotFoundIfShouldFail(
+ () ->
+ client.writeAtLeastOnce(
+ Collections.singletonList(Mutation.delete("FOO", KeySet.all()))));
}
@Test
@@ -1479,39 +1232,36 @@ public void asyncRunnerReadUsingIndex() throws InterruptedException {
private void asyncRunner_withReadFunction(
final Function readFunction) throws InterruptedException {
- invalidateSessionPool();
final ExecutorService queryExecutor = Executors.newSingleThreadExecutor();
try {
AsyncRunner runner = client.runAsync();
final AtomicLong counter = new AtomicLong();
- ApiFuture count =
- runner.runAsync(
- txn -> {
- AsyncResultSet rs = readFunction.apply(txn);
- ApiFuture fut =
- rs.setCallback(
- queryExecutor,
- resultSet -> {
- while (true) {
- switch (resultSet.tryNext()) {
- case OK:
- counter.incrementAndGet();
- break;
- case DONE:
- return CallbackResponse.DONE;
- case NOT_READY:
- return CallbackResponse.CONTINUE;
- }
- }
- });
- return ApiFutures.transform(
- fut, input -> counter.get(), MoreExecutors.directExecutor());
- },
- executor);
- assertThat(get(count)).isEqualTo(2);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
+ assertThrowsSessionNotFoundIfShouldFail(
+ () ->
+ get(
+ runner.runAsync(
+ txn -> {
+ AsyncResultSet rs = readFunction.apply(txn);
+ ApiFuture fut =
+ rs.setCallback(
+ queryExecutor,
+ resultSet -> {
+ while (true) {
+ switch (resultSet.tryNext()) {
+ case OK:
+ counter.incrementAndGet();
+ break;
+ case DONE:
+ return CallbackResponse.DONE;
+ case NOT_READY:
+ return CallbackResponse.CONTINUE;
+ }
+ }
+ });
+ return ApiFutures.transform(
+ fut, input -> counter.get(), MoreExecutors.directExecutor());
+ },
+ executor)));
} finally {
queryExecutor.shutdown();
}
@@ -1519,86 +1269,58 @@ private void asyncRunner_withReadFunction(
@Test
public void asyncRunnerReadRow() throws InterruptedException {
- invalidateSessionPool();
- try {
- AsyncRunner runner = client.runAsync();
- ApiFuture row =
- runner.runAsync(
- txn -> txn.readRowAsync("FOO", Key.of(), Collections.singletonList("BAR")), executor);
- assertThat(get(row).getLong(0)).isEqualTo(1L);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
- }
+ AsyncRunner runner = client.runAsync();
+ assertThrowsSessionNotFoundIfShouldFail(
+ () ->
+ get(
+ runner.runAsync(
+ txn -> txn.readRowAsync("FOO", Key.of(), Collections.singletonList("BAR")),
+ executor)));
}
@Test
public void asyncRunnerReadRowUsingIndex() throws InterruptedException {
- invalidateSessionPool();
- try {
- AsyncRunner runner = client.runAsync();
- ApiFuture row =
- runner.runAsync(
- txn ->
- txn.readRowUsingIndexAsync(
- "FOO", "IDX", Key.of(), Collections.singletonList("BAR")),
- executor);
- assertThat(get(row).getLong(0)).isEqualTo(1L);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
- }
+ AsyncRunner runner = client.runAsync();
+ assertThrowsSessionNotFoundIfShouldFail(
+ () ->
+ get(
+ runner.runAsync(
+ txn ->
+ txn.readRowUsingIndexAsync(
+ "FOO", "IDX", Key.of(), Collections.singletonList("BAR")),
+ executor)));
}
@Test
public void asyncRunnerUpdate() throws InterruptedException {
- invalidateSessionPool();
- try {
- AsyncRunner runner = client.runAsync();
- ApiFuture count =
- runner.runAsync(txn -> txn.executeUpdateAsync(UPDATE_STATEMENT), executor);
- assertThat(get(count)).isEqualTo(UPDATE_COUNT);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
- }
+ AsyncRunner runner = client.runAsync();
+ assertThrowsSessionNotFoundIfShouldFail(
+ () -> get(runner.runAsync(txn -> txn.executeUpdateAsync(UPDATE_STATEMENT), executor)));
}
@Test
public void asyncRunnerBatchUpdate() throws InterruptedException {
- invalidateSessionPool();
- try {
- AsyncRunner runner = client.runAsync();
- ApiFuture count =
- runner.runAsync(
- txn -> txn.batchUpdateAsync(Arrays.asList(UPDATE_STATEMENT, UPDATE_STATEMENT)),
- executor);
- assertThat(get(count)).hasLength(2);
- assertThat(get(count)).asList().containsExactly(UPDATE_COUNT, UPDATE_COUNT);
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
- }
+ AsyncRunner runner = client.runAsync();
+ assertThrowsSessionNotFoundIfShouldFail(
+ () ->
+ get(
+ runner.runAsync(
+ txn -> txn.batchUpdateAsync(Arrays.asList(UPDATE_STATEMENT, UPDATE_STATEMENT)),
+ executor)));
}
@Test
public void asyncRunnerBuffer() throws InterruptedException {
- invalidateSessionPool();
- try {
- AsyncRunner runner = client.runAsync();
- ApiFuture res =
- runner.runAsync(
- txn -> {
- txn.buffer(Mutation.newInsertBuilder("FOO").set("BAR").to(1L).build());
- return ApiFutures.immediateFuture(null);
- },
- executor);
- assertThat(get(res)).isNull();
- assertThat(get(runner.getCommitTimestamp())).isNotNull();
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
- }
+ AsyncRunner runner = client.runAsync();
+ assertThrowsSessionNotFoundIfShouldFail(
+ () ->
+ get(
+ runner.runAsync(
+ txn -> {
+ txn.buffer(Mutation.newInsertBuilder("FOO").set("BAR").to(1L).build());
+ return ApiFutures.immediateFuture(null);
+ },
+ executor)));
}
@Test
@@ -1622,7 +1344,6 @@ public void asyncTransactionManagerAsyncReadUsingIndex() throws InterruptedExcep
private void asyncTransactionManager_readAsync(
final Function fn) throws InterruptedException {
- invalidateSessionPool();
final ExecutorService queryExecutor = Executors.newSingleThreadExecutor();
try (AsyncTransactionManager manager = client.transactionManagerAsync()) {
TransactionContextFuture context = manager.beginAsync();
@@ -1654,16 +1375,12 @@ private void asyncTransactionManager_readAsync(
},
executor);
CommitTimestampFuture ts = count.commitAsync();
- assertThat(get(ts)).isNotNull();
- assertThat(get(count)).isEqualTo(2);
- assertThat(failOnInvalidatedSession).isFalse();
+ assertThrowsSessionNotFoundIfShouldFail(() -> get(ts));
break;
} catch (AbortedException e) {
context = manager.resetForRetryAsync();
}
}
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
} finally {
queryExecutor.shutdown();
}
@@ -1689,7 +1406,6 @@ public void asyncTransactionManagerReadUsingIndex() throws InterruptedException
private void asyncTransactionManager_readSync(final Function fn)
throws InterruptedException {
- invalidateSessionPool();
final ExecutorService queryExecutor = Executors.newSingleThreadExecutor();
try (AsyncTransactionManager manager = client.transactionManagerAsync()) {
TransactionContextFuture context = manager.beginAsync();
@@ -1708,16 +1424,12 @@ private void asyncTransactionManager_readSync(final Function get(ts));
break;
} catch (AbortedException e) {
context = manager.resetForRetryAsync();
}
}
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
} finally {
queryExecutor.shutdown();
}
@@ -1756,7 +1468,6 @@ public void asyncTransactionManagerReadRowUsingIndexAsync() throws InterruptedEx
private void asyncTransactionManager_readRowFunction(
final Function> fn) throws InterruptedException {
- invalidateSessionPool();
final ExecutorService queryExecutor = Executors.newSingleThreadExecutor();
try (AsyncTransactionManager manager = client.transactionManagerAsync()) {
TransactionContextFuture context = manager.beginAsync();
@@ -1765,16 +1476,12 @@ private void asyncTransactionManager_readRowFunction(
AsyncTransactionStep row =
context.then((transaction, ignored) -> fn.apply(transaction), executor);
CommitTimestampFuture ts = row.commitAsync();
- assertThat(get(ts)).isNotNull();
- assertThat(get(row)).isEqualTo(Struct.newBuilder().set("BAR").to(1L).build());
- assertThat(failOnInvalidatedSession).isFalse();
+ assertThrowsSessionNotFoundIfShouldFail(() -> get(ts));
break;
} catch (AbortedException e) {
context = manager.resetForRetryAsync();
}
}
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
} finally {
queryExecutor.shutdown();
}
@@ -1810,7 +1517,6 @@ public void asyncTransactionManagerBatchUpdate() throws InterruptedException {
private void asyncTransactionManager_updateFunction(
final Function> fn, T expected) throws InterruptedException {
- invalidateSessionPool();
try (AsyncTransactionManager manager = client.transactionManagerAsync()) {
TransactionContextFuture transaction = manager.beginAsync();
while (true) {
@@ -1818,16 +1524,12 @@ private void asyncTransactionManager_updateFunction(
AsyncTransactionStep res =
transaction.then((txn, input) -> fn.apply(txn), executor);
CommitTimestampFuture ts = res.commitAsync();
- assertThat(get(res)).isEqualTo(expected);
- assertThat(get(ts)).isNotNull();
+ assertThrowsSessionNotFoundIfShouldFail(() -> get(ts));
break;
} catch (AbortedException e) {
transaction = manager.resetForRetryAsync();
}
}
- assertThat(failOnInvalidatedSession).isFalse();
- } catch (SessionNotFoundException e) {
- assertThat(failOnInvalidatedSession).isTrue();
}
}
}
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerGaxRetryTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerGaxRetryTest.java
index 5dfde3503a..ad45f9039a 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerGaxRetryTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerGaxRetryTest.java
@@ -130,8 +130,7 @@ public void setUp() throws Exception {
.setChannelProvider(channelProvider)
.setCredentials(NoCredentials.getInstance());
// Make sure the session pool is empty by default.
- builder.setSessionPoolOption(
- SessionPoolOptions.newBuilder().setMinSessions(0).setWriteSessionsFraction(0.0f).build());
+ builder.setSessionPoolOption(SessionPoolOptions.newBuilder().setMinSessions(0).build());
// Create one client with default timeout values and one with short timeout values specifically
// for the test cases that expect a DEADLINE_EXCEEDED.
spanner = builder.build().getService();
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/AbstractMockServerTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/AbstractMockServerTest.java
index 154384e2e5..6cf838845b 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/AbstractMockServerTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/AbstractMockServerTest.java
@@ -53,7 +53,6 @@
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
-import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
@@ -113,10 +112,10 @@ public abstract class AbstractMockServerTest {
private static Server server;
private static InetSocketAddress address;
- private boolean futureParentHandlers;
- private boolean exceptionRunnableParentHandlers;
- private boolean nettyServerParentHandlers;
- private boolean clientStreamParentHandlers;
+ private static boolean futureParentHandlers;
+ private static boolean exceptionRunnableParentHandlers;
+ private static boolean nettyServerParentHandlers;
+ private static boolean clientStreamParentHandlers;
@BeforeClass
public static void startStaticServer() throws IOException {
@@ -152,18 +151,6 @@ public void getOperation(
mockSpanner.putStatementResult(StatementResult.update(INSERT_STATEMENT, UPDATE_COUNT));
mockSpanner.putStatementResult(
StatementResult.query(SELECT_RANDOM_STATEMENT, RANDOM_RESULT_SET));
- }
-
- @AfterClass
- public static void stopServer() {
- server.shutdown();
- }
-
- @Before
- public void setupResults() {
- mockSpanner.reset();
- mockDatabaseAdmin.reset();
- mockInstanceAdmin.reset();
futureParentHandlers = Logger.getLogger(AbstractFuture.class.getName()).getUseParentHandlers();
exceptionRunnableParentHandlers =
@@ -181,8 +168,8 @@ public void setupResults() {
Logger.getLogger("io.grpc.internal.AbstractClientStream").setUseParentHandlers(false);
}
- @After
- public void closeSpannerPool() {
+ @AfterClass
+ public static void stopServer() {
try {
SpannerPool.INSTANCE.checkAndCloseSpanners(
CheckAndCloseSpannersMode.ERROR,
@@ -196,6 +183,14 @@ public void closeSpannerPool() {
Logger.getLogger("io.grpc.internal.AbstractClientStream")
.setUseParentHandlers(clientStreamParentHandlers);
}
+ server.shutdown();
+ }
+
+ @Before
+ public void setupResults() {
+ mockSpanner.clearRequests();
+ mockDatabaseAdmin.getRequests().clear();
+ mockInstanceAdmin.getRequests().clear();
}
protected java.sql.Connection createJdbcConnection() throws SQLException {
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/AbstractSqlScriptVerifier.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/AbstractSqlScriptVerifier.java
index 2eb3087089..f247b2d630 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/AbstractSqlScriptVerifier.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/AbstractSqlScriptVerifier.java
@@ -28,6 +28,7 @@
import com.google.cloud.Timestamp;
import com.google.cloud.spanner.ResultSet;
import com.google.cloud.spanner.SpannerException;
+import com.google.cloud.spanner.SpannerExceptionFactory;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
@@ -38,6 +39,7 @@
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import java.util.stream.Stream;
/**
* Base class for SQL Script verifiers for both the generic Connection API and JDBC connections
@@ -180,8 +182,6 @@ public static List readStatementsFromFile(String filename, Class> reso
private final GenericConnectionProvider connectionProvider;
- private final Map variables = new HashMap<>();
-
private final boolean logStatements;
/**
@@ -212,9 +212,12 @@ public AbstractSqlScriptVerifier(GenericConnectionProvider provider) {
* semicolon (;)
* @param resourceClass The class that should be used to locate the resource specified by the file
* name
+ * @param allowParallel indicates whether the batches in the given script may be executed in
+ * parallel
*/
- public void verifyStatementsInFile(String filename, Class> resourceClass) throws Exception {
- verifyStatementsInFile(connectionProvider.getConnection(), filename, resourceClass);
+ public void verifyStatementsInFile(String filename, Class> resourceClass, boolean allowParallel)
+ throws Exception {
+ verifyStatementsInFile(null, filename, resourceClass, allowParallel);
}
/**
@@ -223,42 +226,80 @@ public void verifyStatementsInFile(String filename, Class> resourceClass) thro
* Statements without an @EXPECT statement will be executed and its result will be ignored, unless
* the statement throws an exception, which will fail the test case.
*
- * @param connection The {@link com.google.cloud.spanner.jdbc.Connection} to execute the
+ * @param providedConnection The {@link com.google.cloud.spanner.jdbc.Connection} to execute the
* statements against
* @param filename The file name containing the statements. Statements must be separated by a
* semicolon (;)
* @param resourceClass The class that defines the package where to find the input file
+ * @param allowParallel indicates whether the batches in the given script may be executed in
+ * parallel
*/
public void verifyStatementsInFile(
- GenericConnection connection, String filename, Class> resourceClass) throws Exception {
- try {
- List statements = readStatementsFromFile(filename, resourceClass);
- for (String statement : statements) {
- String sql = statement.trim();
- if (logStatements) {
- System.out.println(
- "\n------------------------------------------------------\n"
- + new Date()
- + " ---- verifying statement:");
- System.out.println(sql);
- }
- if (sql.equalsIgnoreCase("NEW_CONNECTION")) {
- connection.close();
- connection = connectionProvider.getConnection();
- variables.clear();
- } else {
- verifyStatement(connection, sql);
+ GenericConnection providedConnection,
+ String filename,
+ Class> resourceClass,
+ boolean allowParallel)
+ throws Exception {
+ List statements = readStatementsFromFile(filename, resourceClass);
+ List> batches = toBatches(statements);
+
+ Stream> stream;
+ if (!allowParallel || logStatements) {
+ stream = batches.stream();
+ } else {
+ stream = batches.parallelStream();
+ }
+ stream.forEach(
+ batch -> {
+ try {
+ Map variables = new HashMap<>();
+ GenericConnection connection;
+ if (providedConnection == null) {
+ connection = connectionProvider.getConnection();
+ } else {
+ connection = providedConnection;
+ }
+ for (String sql : batch) {
+ if (logStatements) {
+ System.out.println(
+ "\n------------------------------------------------------\n"
+ + new Date()
+ + " ---- verifying statement:");
+ System.out.println(sql);
+ }
+ verifyStatement(variables, connection, sql);
+ }
+ connection.close();
+ } catch (Exception e) {
+ throw SpannerExceptionFactory.asSpannerException(e);
+ }
+ });
+ }
+
+ private List> toBatches(List statements) {
+ List> batches = new ArrayList<>();
+ List currentBatch = new ArrayList<>();
+ for (String statement : statements) {
+ String sql = statement.trim();
+ if (sql.equalsIgnoreCase("NEW_CONNECTION")) {
+ if (!currentBatch.isEmpty()) {
+ batches.add(currentBatch);
}
- }
- } finally {
- if (connection != null) {
- connection.close();
+ currentBatch = new ArrayList<>();
+ } else {
+ currentBatch.add(sql);
}
}
+ if (!currentBatch.isEmpty()) {
+ batches.add(currentBatch);
+ }
+ return batches;
}
- private void verifyStatement(GenericConnection connection, String statement) throws Exception {
- statement = replaceVariables(statement);
+ private void verifyStatement(
+ Map variables, GenericConnection connection, String statement)
+ throws Exception {
+ statement = replaceVariables(variables, statement);
String statementWithoutComments = StatementParser.removeCommentsAndTrim(statement);
Matcher verifyMatcher = VERIFY_PATTERN.matcher(statementWithoutComments);
Matcher putMatcher = PUT_PATTERN.matcher(statementWithoutComments);
@@ -350,7 +391,7 @@ private void verifyStatement(GenericConnection connection, String statement) thr
}
}
- private String replaceVariables(String sql) {
+ private String replaceVariables(Map variables, String sql) {
for (String key : variables.keySet()) {
sql = sql.replaceAll("%%" + key + "%%", variables.get(key).toString());
}
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ClientSideStatementsTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ClientSideStatementsTest.java
index b36da9c7ac..eab1424814 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ClientSideStatementsTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ClientSideStatementsTest.java
@@ -49,7 +49,7 @@ public class ClientSideStatementsTest {
@Test
public void testExecuteClientSideStatementsScript() throws Exception {
SqlScriptVerifier verifier = new SqlScriptVerifier(new TestConnectionProvider());
- verifier.verifyStatementsInFile("ClientSideStatementsTest.sql", getClass());
+ verifier.verifyStatementsInFile("ClientSideStatementsTest.sql", getClass(), true);
}
private static final String SCRIPT_FILE =
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionAsyncApiTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionAsyncApiTest.java
index ca16259f68..ff409e88c6 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionAsyncApiTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionAsyncApiTest.java
@@ -18,6 +18,9 @@
import static com.google.cloud.spanner.SpannerApiFutures.get;
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
import static org.junit.Assert.fail;
import com.google.api.core.ApiFuture;
@@ -26,18 +29,21 @@
import com.google.cloud.spanner.AsyncResultSet.CallbackResponse;
import com.google.cloud.spanner.AsyncResultSet.ReadyCallback;
import com.google.cloud.spanner.ErrorCode;
+import com.google.cloud.spanner.ForceCloseSpannerFunction;
import com.google.cloud.spanner.MockSpannerServiceImpl.SimulatedExecutionTime;
import com.google.cloud.spanner.Mutation;
import com.google.cloud.spanner.ResultSet;
import com.google.cloud.spanner.SpannerApiFutures;
import com.google.cloud.spanner.SpannerException;
import com.google.cloud.spanner.Statement;
+import com.google.cloud.spanner.connection.SpannerPool.CheckAndCloseSpannersMode;
import com.google.cloud.spanner.connection.StatementResult.ResultType;
import com.google.common.base.Function;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.protobuf.AbstractMessage;
+import com.google.spanner.v1.CommitRequest;
import com.google.spanner.v1.ExecuteBatchDmlRequest;
import com.google.spanner.v1.ExecuteSqlRequest;
import java.util.List;
@@ -54,7 +60,7 @@
@RunWith(JUnit4.class)
public class ConnectionAsyncApiTest extends AbstractMockServerTest {
- private static final ExecutorService executor = Executors.newSingleThreadExecutor();
+ private static ExecutorService executor = Executors.newSingleThreadExecutor();
private static final Function AUTOCOMMIT =
input -> {
input.setAutocommit(true);
@@ -75,6 +81,8 @@ public static void stopExecutor() {
@After
public void reset() {
mockSpanner.removeAllExecutionTimes();
+ executor.shutdownNow();
+ executor = Executors.newSingleThreadExecutor();
}
@Test
@@ -258,20 +266,32 @@ public CallbackResponse cursorReady(AsyncResultSet resultSet) {
}
});
}
- connection.commitAsync();
+ ApiFuture commit = connection.commitAsync();
assertThat(get(update1)).isEqualTo(UPDATE_COUNT);
assertThat(get(update2)).isEqualTo(UPDATE_COUNT);
assertThat(get(batch)).asList().containsExactly(1L, 1L);
assertThat(get(rowCount)).isEqualTo(RANDOM_RESULT_SET_ROW_COUNT);
+ assertNull(get(commit));
+ // Get the last commit request.
+ CommitRequest commitRequest =
+ mockSpanner.getRequestsOfType(CommitRequest.class).stream()
+ .reduce((first, second) -> second)
+ .get();
// Verify the order of the statements on the server.
List extends AbstractMessage> requests =
Lists.newArrayList(
Collections2.filter(
mockSpanner.getRequests(),
input ->
- input instanceof ExecuteSqlRequest
- || input instanceof ExecuteBatchDmlRequest));
+ (input instanceof ExecuteSqlRequest
+ && ((ExecuteSqlRequest) input)
+ .getSession()
+ .equals(commitRequest.getSession()))
+ || (input instanceof ExecuteBatchDmlRequest
+ && ((ExecuteBatchDmlRequest) input)
+ .getSession()
+ .equals(commitRequest.getSession()))));
assertThat(requests).hasSize(4);
assertThat(requests.get(0)).isInstanceOf(ExecuteSqlRequest.class);
assertThat(((ExecuteSqlRequest) requests.get(0)).getSeqno()).isEqualTo(1L);
@@ -326,12 +346,13 @@ public void testExecuteDdlAsync() {
@Test
public void testExecuteInvalidStatementAsync() {
try (Connection connection = createConnection()) {
- try {
- connection.executeAsync(Statement.of("UPSERT INTO FOO (ID, VAL) VALUES (1, 'foo')"));
- fail("Missing expected exception");
- } catch (SpannerException e) {
- assertThat(e.getErrorCode()).isEqualTo(ErrorCode.INVALID_ARGUMENT);
- }
+ SpannerException e =
+ assertThrows(
+ SpannerException.class,
+ () ->
+ connection.executeAsync(
+ Statement.of("UPSERT INTO FOO (ID, VAL) VALUES (1, 'foo')")));
+ assertEquals(ErrorCode.INVALID_ARGUMENT, e.getErrorCode());
}
}
@@ -657,6 +678,10 @@ private void testExecuteBatchUpdate(Function connectionConfigu
}
}
}
+ // Close the Spanner pool to prevent requests from this test from interfering with other tests.
+ SpannerPool.INSTANCE.checkAndCloseSpanners(
+ CheckAndCloseSpannersMode.ERROR,
+ new ForceCloseSpannerFunction(100L, TimeUnit.MILLISECONDS));
}
private void testWriteAsync(Function connectionConfigurator) {
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionImplGeneratedSqlScriptTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionImplGeneratedSqlScriptTest.java
index 90dc3ad9bb..bfa023c1dd 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionImplGeneratedSqlScriptTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionImplGeneratedSqlScriptTest.java
@@ -63,7 +63,7 @@ public GenericConnection getConnection() {
@Test
public void testGeneratedScript() throws Exception {
SqlScriptVerifier verifier = new SqlScriptVerifier(new TestConnectionProvider());
- verifier.verifyStatementsInFile("ConnectionImplGeneratedSqlScriptTest.sql", getClass());
+ verifier.verifyStatementsInFile("ConnectionImplGeneratedSqlScriptTest.sql", getClass(), true);
}
/**
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SetReadOnlyStalenessSqlScriptTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SetReadOnlyStalenessSqlScriptTest.java
index a317630ebd..25aad948fe 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SetReadOnlyStalenessSqlScriptTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SetReadOnlyStalenessSqlScriptTest.java
@@ -42,6 +42,6 @@ public GenericConnection getConnection() {
@Test
public void testSetReadOnlyStalenessScript() throws Exception {
SqlScriptVerifier verifier = new SqlScriptVerifier(new TestConnectionProvider());
- verifier.verifyStatementsInFile("SetReadOnlyStalenessTest.sql", getClass());
+ verifier.verifyStatementsInFile("SetReadOnlyStalenessTest.sql", getClass(), true);
}
}
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SetStatementTimeoutSqlScriptTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SetStatementTimeoutSqlScriptTest.java
index ea70384d96..c47fde41c1 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SetStatementTimeoutSqlScriptTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SetStatementTimeoutSqlScriptTest.java
@@ -42,6 +42,6 @@ public GenericConnection getConnection() {
@Test
public void testSetStatementTimeoutScript() throws Exception {
SqlScriptVerifier verifier = new SqlScriptVerifier(new TestConnectionProvider());
- verifier.verifyStatementsInFile("SetStatementTimeoutTest.sql", getClass());
+ verifier.verifyStatementsInFile("SetStatementTimeoutTest.sql", getClass(), true);
}
}
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/StatementTimeoutTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/StatementTimeoutTest.java
index 87fde11f9b..08f47c0c5d 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/StatementTimeoutTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/StatementTimeoutTest.java
@@ -18,11 +18,13 @@
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+import com.google.api.core.SettableApiFuture;
import com.google.api.gax.longrunning.OperationTimedPollAlgorithm;
import com.google.api.gax.retrying.RetrySettings;
import com.google.cloud.spanner.ErrorCode;
@@ -33,12 +35,14 @@
import com.google.cloud.spanner.Statement;
import com.google.cloud.spanner.connection.AbstractConnectionImplTest.ConnectionConsumer;
import com.google.cloud.spanner.connection.ITAbstractSpannerTest.ITConnection;
-import com.google.common.util.concurrent.Uninterruptibles;
+import com.google.common.base.Stopwatch;
+import com.google.common.collect.Collections2;
import com.google.longrunning.Operation;
import com.google.protobuf.AbstractMessage;
import com.google.protobuf.Any;
import com.google.protobuf.Empty;
import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata;
+import com.google.spanner.admin.database.v1.UpdateDatabaseDdlRequest;
import com.google.spanner.v1.CommitRequest;
import com.google.spanner.v1.ExecuteSqlRequest;
import io.grpc.Status;
@@ -115,12 +119,10 @@ public void testTimeoutExceptionReadOnlyAutocommit() {
connection.setAutocommit(true);
connection.setReadOnly(true);
connection.setStatementTimeout(TIMEOUT_FOR_SLOW_STATEMENTS, TimeUnit.MILLISECONDS);
- try {
- connection.executeQuery(SELECT_RANDOM_STATEMENT);
- fail("missing expected exception");
- } catch (SpannerException ex) {
- assertEquals(ErrorCode.DEADLINE_EXCEEDED, ex.getErrorCode());
- }
+ SpannerException e =
+ assertThrows(
+ SpannerException.class, () -> connection.executeQuery(SELECT_RANDOM_STATEMENT));
+ assertEquals(ErrorCode.DEADLINE_EXCEEDED, e.getErrorCode());
}
}
@@ -135,18 +137,16 @@ public void testTimeoutExceptionReadOnlyAutocommitMultipleStatements() {
connection.setStatementTimeout(TIMEOUT_FOR_SLOW_STATEMENTS, TimeUnit.MILLISECONDS);
// assert that multiple statements after each other also time out
for (int i = 0; i < 2; i++) {
- try {
- connection.executeQuery(SELECT_RANDOM_STATEMENT);
- fail("missing expected exception");
- } catch (SpannerException e) {
- assertEquals(ErrorCode.DEADLINE_EXCEEDED, e.getErrorCode());
- }
+ SpannerException e =
+ assertThrows(
+ SpannerException.class, () -> connection.executeQuery(SELECT_RANDOM_STATEMENT));
+ assertEquals(ErrorCode.DEADLINE_EXCEEDED, e.getErrorCode());
}
// try to do a new query that is fast.
mockSpanner.removeAllExecutionTimes();
connection.setStatementTimeout(TIMEOUT_FOR_FAST_STATEMENTS, TimeUnit.MILLISECONDS);
try (ResultSet rs = connection.executeQuery(SELECT_RANDOM_STATEMENT)) {
- assertThat(rs, is(notNullValue()));
+ assertNotNull(rs);
}
}
}
@@ -160,12 +160,10 @@ public void testTimeoutExceptionReadOnlyTransactional() {
connection.setReadOnly(true);
connection.setAutocommit(false);
connection.setStatementTimeout(TIMEOUT_FOR_SLOW_STATEMENTS, TimeUnit.MILLISECONDS);
- try {
- connection.executeQuery(SELECT_RANDOM_STATEMENT);
- fail("missing expected exception");
- } catch (SpannerException ex) {
- assertEquals(ErrorCode.DEADLINE_EXCEEDED, ex.getErrorCode());
- }
+ SpannerException e =
+ assertThrows(
+ SpannerException.class, () -> connection.executeQuery(SELECT_RANDOM_STATEMENT));
+ assertEquals(ErrorCode.DEADLINE_EXCEEDED, e.getErrorCode());
}
}
@@ -180,12 +178,10 @@ public void testTimeoutExceptionReadOnlyTransactionMultipleStatements() {
connection.setStatementTimeout(TIMEOUT_FOR_SLOW_STATEMENTS, TimeUnit.MILLISECONDS);
// assert that multiple statements after each other also time out
for (int i = 0; i < 2; i++) {
- try {
- connection.executeQuery(SELECT_RANDOM_STATEMENT);
- fail("missing expected exception");
- } catch (SpannerException e) {
- assertEquals(ErrorCode.DEADLINE_EXCEEDED, e.getErrorCode());
- }
+ SpannerException e =
+ assertThrows(
+ SpannerException.class, () -> connection.executeQuery(SELECT_RANDOM_STATEMENT));
+ assertEquals(ErrorCode.DEADLINE_EXCEEDED, e.getErrorCode());
}
// do a rollback without any chance of a timeout
connection.clearStatementTimeout();
@@ -194,7 +190,7 @@ public void testTimeoutExceptionReadOnlyTransactionMultipleStatements() {
mockSpanner.removeAllExecutionTimes();
connection.setStatementTimeout(TIMEOUT_FOR_FAST_STATEMENTS, TimeUnit.MILLISECONDS);
try (ResultSet rs = connection.executeQuery(SELECT_RANDOM_STATEMENT)) {
- assertThat(rs, is(notNullValue()));
+ assertNotNull(rs);
}
}
}
@@ -207,12 +203,10 @@ public void testTimeoutExceptionReadWriteAutocommit() {
try (Connection connection = createConnection()) {
connection.setAutocommit(true);
connection.setStatementTimeout(TIMEOUT_FOR_SLOW_STATEMENTS, TimeUnit.MILLISECONDS);
- try {
- connection.executeQuery(SELECT_RANDOM_STATEMENT);
- fail("missing expected exception");
- } catch (SpannerException ex) {
- assertEquals(ErrorCode.DEADLINE_EXCEEDED, ex.getErrorCode());
- }
+ SpannerException e =
+ assertThrows(
+ SpannerException.class, () -> connection.executeQuery(SELECT_RANDOM_STATEMENT));
+ assertEquals(ErrorCode.DEADLINE_EXCEEDED, e.getErrorCode());
}
}
@@ -226,18 +220,16 @@ public void testTimeoutExceptionReadWriteAutocommitMultipleStatements() {
connection.setStatementTimeout(TIMEOUT_FOR_SLOW_STATEMENTS, TimeUnit.MILLISECONDS);
// assert that multiple statements after each other also time out
for (int i = 0; i < 2; i++) {
- try {
- connection.executeQuery(SELECT_RANDOM_STATEMENT);
- fail("missing expected exception");
- } catch (SpannerException e) {
- assertEquals(ErrorCode.DEADLINE_EXCEEDED, e.getErrorCode());
- }
+ SpannerException e =
+ assertThrows(
+ SpannerException.class, () -> connection.executeQuery(SELECT_RANDOM_STATEMENT));
+ assertEquals(ErrorCode.DEADLINE_EXCEEDED, e.getErrorCode());
}
// try to do a new query that is fast.
mockSpanner.removeAllExecutionTimes();
connection.setStatementTimeout(TIMEOUT_FOR_FAST_STATEMENTS, TimeUnit.MILLISECONDS);
try (ResultSet rs = connection.executeQuery(SELECT_RANDOM_STATEMENT)) {
- assertThat(rs, is(notNullValue()));
+ assertNotNull(rs);
}
}
}
@@ -250,12 +242,9 @@ public void testTimeoutExceptionReadWriteAutocommitSlowUpdate() {
try (Connection connection = createConnection()) {
connection.setAutocommit(true);
connection.setStatementTimeout(TIMEOUT_FOR_SLOW_STATEMENTS, TimeUnit.MILLISECONDS);
- try {
- connection.execute(INSERT_STATEMENT);
- fail("Missing expected exception");
- } catch (SpannerException ex) {
- assertEquals(ErrorCode.DEADLINE_EXCEEDED, ex.getErrorCode());
- }
+ SpannerException e =
+ assertThrows(SpannerException.class, () -> connection.execute(INSERT_STATEMENT));
+ assertEquals(ErrorCode.DEADLINE_EXCEEDED, e.getErrorCode());
}
}
@@ -270,17 +259,15 @@ public void testTimeoutExceptionReadWriteAutocommitSlowUpdateMultipleStatements(
// assert that multiple statements after each other also time out
for (int i = 0; i < 2; i++) {
- try {
- connection.execute(Statement.of(SLOW_UPDATE));
- fail("missing expected exception");
- } catch (SpannerException e) {
- assertEquals(ErrorCode.DEADLINE_EXCEEDED, e.getErrorCode());
- }
+ SpannerException e =
+ assertThrows(
+ SpannerException.class, () -> connection.execute(Statement.of(SLOW_UPDATE)));
+ assertEquals(ErrorCode.DEADLINE_EXCEEDED, e.getErrorCode());
}
// try to do a new update that is fast.
mockSpanner.removeAllExecutionTimes();
connection.setStatementTimeout(TIMEOUT_FOR_FAST_STATEMENTS, TimeUnit.MILLISECONDS);
- assertThat(connection.execute(INSERT_STATEMENT).getUpdateCount(), is(equalTo(UPDATE_COUNT)));
+ assertEquals(UPDATE_COUNT, connection.execute(INSERT_STATEMENT).getUpdateCount().longValue());
}
}
@@ -301,12 +288,9 @@ public void testTimeoutExceptionReadWriteAutocommitSlowCommit() {
// gRPC call will be slow.
connection.setStatementTimeout(TIMEOUT_FOR_SLOW_STATEMENTS, TimeUnit.MILLISECONDS);
connection.setAutocommit(true);
- try {
- connection.execute(INSERT_STATEMENT);
- fail("missing expected exception");
- } catch (SpannerException ex) {
- assertEquals(ErrorCode.DEADLINE_EXCEEDED, ex.getErrorCode());
- }
+ SpannerException e =
+ assertThrows(SpannerException.class, () -> connection.execute(INSERT_STATEMENT));
+ assertEquals(ErrorCode.DEADLINE_EXCEEDED, e.getErrorCode());
}
}
@@ -320,18 +304,15 @@ public void testTimeoutExceptionReadWriteAutocommitSlowCommitMultipleStatements(
connection.setStatementTimeout(TIMEOUT_FOR_SLOW_STATEMENTS, TimeUnit.MILLISECONDS);
// assert that multiple statements after each other also time out
for (int i = 0; i < 2; i++) {
- try {
- connection.execute(INSERT_STATEMENT);
- fail("Missing expected exception");
- } catch (SpannerException e) {
- assertThat(e.getErrorCode(), is(equalTo(ErrorCode.DEADLINE_EXCEEDED)));
- }
+ SpannerException e =
+ assertThrows(SpannerException.class, () -> connection.execute(INSERT_STATEMENT));
+ assertEquals(ErrorCode.DEADLINE_EXCEEDED, e.getErrorCode());
}
// try to do a query in autocommit mode. This will use a single-use read-only transaction that
// does not need to commit, i.e. it should succeed.
connection.setStatementTimeout(TIMEOUT_FOR_FAST_STATEMENTS, TimeUnit.MILLISECONDS);
try (ResultSet rs = connection.executeQuery(SELECT_RANDOM_STATEMENT)) {
- assertThat(rs, is(notNullValue()));
+ assertNotNull(rs);
}
}
}
@@ -350,12 +331,9 @@ public void testTimeoutExceptionReadWriteAutocommitPartitioned() {
mockSpanner.setExecuteStreamingSqlExecutionTime(
SimulatedExecutionTime.ofMinimumAndRandomTime(EXECUTION_TIME_SLOW_STATEMENT, 0));
connection.setStatementTimeout(TIMEOUT_FOR_SLOW_STATEMENTS, TimeUnit.MILLISECONDS);
- try {
- connection.execute(INSERT_STATEMENT);
- fail("Missing expected exception");
- } catch (SpannerException ex) {
- assertEquals(ErrorCode.DEADLINE_EXCEEDED, ex.getErrorCode());
- }
+ SpannerException e =
+ assertThrows(SpannerException.class, () -> connection.execute(INSERT_STATEMENT));
+ assertEquals(ErrorCode.DEADLINE_EXCEEDED, e.getErrorCode());
}
}
@@ -367,12 +345,10 @@ public void testTimeoutExceptionReadWriteTransactional() {
try (Connection connection = createConnection()) {
connection.setAutocommit(false);
connection.setStatementTimeout(TIMEOUT_FOR_SLOW_STATEMENTS, TimeUnit.MILLISECONDS);
- try {
- connection.executeQuery(SELECT_RANDOM_STATEMENT);
- fail("Missing expected exception");
- } catch (SpannerException ex) {
- assertEquals(ErrorCode.DEADLINE_EXCEEDED, ex.getErrorCode());
- }
+ SpannerException e =
+ assertThrows(
+ SpannerException.class, () -> connection.executeQuery(SELECT_RANDOM_STATEMENT));
+ assertEquals(ErrorCode.DEADLINE_EXCEEDED, e.getErrorCode());
}
}
@@ -387,15 +363,13 @@ public void testTimeoutExceptionReadWriteTransactionMultipleStatements() {
// Assert that multiple statements after each other will timeout the first time, and then
// throw a SpannerException with code FAILED_PRECONDITION.
for (int i = 0; i < 2; i++) {
- try {
- connection.executeQuery(SELECT_RANDOM_STATEMENT);
- fail("Missing expected exception");
- } catch (SpannerException e) {
- if (i == 0) {
- assertThat(e.getErrorCode(), is(equalTo(ErrorCode.DEADLINE_EXCEEDED)));
- } else {
- assertThat(e.getErrorCode(), is(equalTo(ErrorCode.FAILED_PRECONDITION)));
- }
+ SpannerException e =
+ assertThrows(
+ SpannerException.class, () -> connection.executeQuery(SELECT_RANDOM_STATEMENT));
+ if (i == 0) {
+ assertEquals(ErrorCode.DEADLINE_EXCEEDED, e.getErrorCode());
+ } else {
+ assertEquals(ErrorCode.FAILED_PRECONDITION, e.getErrorCode());
}
}
// do a rollback without any chance of a timeout
@@ -405,7 +379,7 @@ public void testTimeoutExceptionReadWriteTransactionMultipleStatements() {
mockSpanner.removeAllExecutionTimes();
connection.setStatementTimeout(TIMEOUT_FOR_FAST_STATEMENTS, TimeUnit.MILLISECONDS);
try (ResultSet rs = connection.executeQuery(SELECT_RANDOM_STATEMENT)) {
- assertThat(rs, is(notNullValue()));
+ assertNotNull(rs);
}
}
}
@@ -420,16 +394,12 @@ public void testTimeoutExceptionReadWriteTransactionalSlowCommit() {
connection.setStatementTimeout(TIMEOUT_FOR_FAST_STATEMENTS, TimeUnit.MILLISECONDS);
try (ResultSet rs = connection.executeQuery(SELECT_RANDOM_STATEMENT)) {
- assertThat(rs, is(notNullValue()));
+ assertNotNull(rs);
}
connection.setStatementTimeout(TIMEOUT_FOR_SLOW_STATEMENTS, TimeUnit.MILLISECONDS);
- try {
- connection.commit();
- fail("Missing expected exception");
- } catch (SpannerException ex) {
- assertEquals(ErrorCode.DEADLINE_EXCEEDED, ex.getErrorCode());
- }
+ SpannerException e = assertThrows(SpannerException.class, () -> connection.commit());
+ assertEquals(ErrorCode.DEADLINE_EXCEEDED, e.getErrorCode());
}
}
@@ -443,7 +413,7 @@ public void testTimeoutExceptionReadWriteTransactionalSlowRollback() {
connection.setStatementTimeout(TIMEOUT_FOR_FAST_STATEMENTS, TimeUnit.MILLISECONDS);
try (ResultSet rs = connection.executeQuery(SELECT_RANDOM_STATEMENT)) {
- assertThat(rs, is(notNullValue()));
+ assertNotNull(rs);
}
connection.setStatementTimeout(TIMEOUT_FOR_SLOW_STATEMENTS, TimeUnit.MILLISECONDS);
// Rollback timeouts are not propagated as exceptions, as all errors during a Rollback RPC are
@@ -513,25 +483,32 @@ private void testInterruptedException(final ConnectionConsumer consumer)
mockSpanner.setExecuteStreamingSqlExecutionTime(
SimulatedExecutionTime.ofMinimumAndRandomTime(EXECUTION_TIME_SLOW_STATEMENT, 0));
- final CountDownLatch latch = new CountDownLatch(1);
+ CountDownLatch latch = new CountDownLatch(1);
+ SettableApiFuture thread = SettableApiFuture.create();
ExecutorService executor = Executors.newSingleThreadExecutor();
- Future future =
- executor.submit(
- () -> {
- try (Connection connection = createConnection()) {
- consumer.accept(connection);
- connection.setStatementTimeout(10000L, TimeUnit.MILLISECONDS);
-
- latch.countDown();
- try (ResultSet rs = connection.executeQuery(SELECT_RANDOM_STATEMENT)) {}
- return false;
- } catch (SpannerException e) {
- return e.getErrorCode() == ErrorCode.CANCELLED;
- }
- });
- latch.await(10L, TimeUnit.SECONDS);
- executor.shutdownNow();
- assertThat(future.get(), is(true));
+ try {
+ Future future =
+ executor.submit(
+ () -> {
+ try (Connection connection = createConnection()) {
+ consumer.accept(connection);
+ connection.setStatementTimeout(10000L, TimeUnit.MILLISECONDS);
+
+ thread.set(Thread.currentThread());
+ latch.countDown();
+ try (ResultSet rs = connection.executeQuery(SELECT_RANDOM_STATEMENT)) {}
+ return false;
+ } catch (SpannerException e) {
+ return e.getErrorCode() == ErrorCode.CANCELLED;
+ }
+ });
+ latch.await(10L, TimeUnit.SECONDS);
+ waitForRequestsToContain(ExecuteSqlRequest.class);
+ thread.get().interrupt();
+ assertTrue(future.get());
+ } finally {
+ executor.shutdownNow();
+ }
}
@Test
@@ -543,12 +520,10 @@ public void testInvalidQueryReadOnlyAutocommit() {
connection.setAutocommit(true);
connection.setReadOnly(true);
connection.setStatementTimeout(TIMEOUT_FOR_FAST_STATEMENTS, TimeUnit.MILLISECONDS);
- try {
- connection.executeQuery(Statement.of(INVALID_SELECT));
- fail("Missing expected exception");
- } catch (SpannerException ex) {
- assertEquals(ErrorCode.INVALID_ARGUMENT, ex.getErrorCode());
- }
+ SpannerException e =
+ assertThrows(
+ SpannerException.class, () -> connection.executeQuery(Statement.of(INVALID_SELECT)));
+ assertEquals(ErrorCode.INVALID_ARGUMENT, e.getErrorCode());
}
}
@@ -561,12 +536,10 @@ public void testInvalidQueryReadOnlyTransactional() {
connection.setReadOnly(true);
connection.setAutocommit(false);
connection.setStatementTimeout(TIMEOUT_FOR_FAST_STATEMENTS, TimeUnit.MILLISECONDS);
- try {
- connection.executeQuery(Statement.of(INVALID_SELECT));
- fail("Missing expected exception");
- } catch (SpannerException ex) {
- assertEquals(ErrorCode.INVALID_ARGUMENT, ex.getErrorCode());
- }
+ SpannerException e =
+ assertThrows(
+ SpannerException.class, () -> connection.executeQuery(Statement.of(INVALID_SELECT)));
+ assertEquals(ErrorCode.INVALID_ARGUMENT, e.getErrorCode());
}
}
@@ -578,12 +551,10 @@ public void testInvalidQueryReadWriteAutocommit() {
try (Connection connection = createConnection()) {
connection.setAutocommit(true);
connection.setStatementTimeout(TIMEOUT_FOR_FAST_STATEMENTS, TimeUnit.MILLISECONDS);
- try {
- connection.executeQuery(Statement.of(INVALID_SELECT));
- fail("Missing expected exception");
- } catch (SpannerException ex) {
- assertEquals(ErrorCode.INVALID_ARGUMENT, ex.getErrorCode());
- }
+ SpannerException e =
+ assertThrows(
+ SpannerException.class, () -> connection.executeQuery(Statement.of(INVALID_SELECT)));
+ assertEquals(ErrorCode.INVALID_ARGUMENT, e.getErrorCode());
}
}
@@ -595,12 +566,10 @@ public void testInvalidQueryReadWriteTransactional() {
try (Connection connection = createConnection()) {
connection.setAutocommit(false);
connection.setStatementTimeout(TIMEOUT_FOR_FAST_STATEMENTS, TimeUnit.MILLISECONDS);
- try {
- connection.executeQuery(Statement.of(INVALID_SELECT));
- fail("Missing expected exception");
- } catch (SpannerException ex) {
- assertEquals(ErrorCode.INVALID_ARGUMENT, ex.getErrorCode());
- }
+ SpannerException e =
+ assertThrows(
+ SpannerException.class, () -> connection.executeQuery(Statement.of(INVALID_SELECT)));
+ assertEquals(ErrorCode.INVALID_ARGUMENT, e.getErrorCode());
}
}
@@ -614,28 +583,48 @@ static void waitForRequestsToContain(Class extends AbstractMessage> request) {
}
}
+ private void waitForDdlRequestOnServer() {
+ try {
+ Stopwatch watch = Stopwatch.createStarted();
+ while (Collections2.filter(
+ mockDatabaseAdmin.getRequests(),
+ input -> input.getClass().equals(UpdateDatabaseDdlRequest.class))
+ .size()
+ == 0) {
+ Thread.sleep(1L);
+ if (watch.elapsed(TimeUnit.MILLISECONDS) > EXECUTION_TIME_SLOW_STATEMENT) {
+ throw new TimeoutException("Timeout while waiting for DDL request");
+ }
+ }
+ } catch (InterruptedException e) {
+ throw SpannerExceptionFactory.propagateInterrupt(e);
+ } catch (TimeoutException e) {
+ throw SpannerExceptionFactory.propagateTimeout(e);
+ }
+ }
+
@Test
public void testCancelReadOnlyAutocommit() {
mockSpanner.setExecuteStreamingSqlExecutionTime(
SimulatedExecutionTime.ofMinimumAndRandomTime(EXECUTION_TIME_SLOW_STATEMENT, 0));
- ExecutorService executor = Executors.newSingleThreadExecutor();
try (Connection connection = createConnection()) {
connection.setAutocommit(true);
connection.setReadOnly(true);
- executor.execute(
- () -> {
- waitForRequestsToContain(ExecuteSqlRequest.class);
- connection.cancel();
- });
+ ExecutorService executor = Executors.newSingleThreadExecutor();
try {
- connection.executeQuery(SELECT_RANDOM_STATEMENT);
- fail("Missing expected exception");
- } catch (SpannerException ex) {
- assertEquals(ErrorCode.CANCELLED, ex.getErrorCode());
+ executor.execute(
+ () -> {
+ waitForRequestsToContain(ExecuteSqlRequest.class);
+ connection.cancel();
+ });
+ SpannerException e =
+ assertThrows(
+ SpannerException.class, () -> connection.executeQuery(SELECT_RANDOM_STATEMENT));
+ assertEquals(ErrorCode.CANCELLED, e.getErrorCode());
+ } finally {
+ executor.shutdownNow();
}
- } finally {
- executor.shutdown();
}
}
@@ -644,29 +633,30 @@ public void testCancelReadOnlyAutocommitMultipleStatements() {
mockSpanner.setExecuteStreamingSqlExecutionTime(
SimulatedExecutionTime.ofMinimumAndRandomTime(EXECUTION_TIME_SLOW_STATEMENT, 0));
- ExecutorService executor = Executors.newSingleThreadExecutor();
try (Connection connection = createConnection()) {
connection.setAutocommit(true);
connection.setReadOnly(true);
- executor.execute(
- () -> {
- waitForRequestsToContain(ExecuteSqlRequest.class);
- connection.cancel();
- });
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ try {
+ executor.execute(
+ () -> {
+ waitForRequestsToContain(ExecuteSqlRequest.class);
+ connection.cancel();
+ });
- try (ResultSet rs = connection.executeQuery(SELECT_RANDOM_STATEMENT)) {
- fail("Missing expected exception");
- } catch (SpannerException e) {
+ SpannerException e =
+ assertThrows(
+ SpannerException.class, () -> connection.executeQuery(SELECT_RANDOM_STATEMENT));
assertThat(e.getErrorCode(), is(equalTo(ErrorCode.CANCELLED)));
- }
- mockSpanner.removeAllExecutionTimes();
- connection.setStatementTimeout(TIMEOUT_FOR_FAST_STATEMENTS, TimeUnit.MILLISECONDS);
- try (ResultSet rs = connection.executeQuery(SELECT_RANDOM_STATEMENT)) {
- assertThat(rs, is(notNullValue()));
+ mockSpanner.removeAllExecutionTimes();
+ connection.setStatementTimeout(TIMEOUT_FOR_FAST_STATEMENTS, TimeUnit.MILLISECONDS);
+ try (ResultSet rs = connection.executeQuery(SELECT_RANDOM_STATEMENT)) {
+ assertNotNull(rs);
+ }
+ } finally {
+ executor.shutdownNow();
}
- } finally {
- executor.shutdown();
}
}
@@ -675,23 +665,23 @@ public void testCancelReadOnlyTransactional() {
mockSpanner.setExecuteStreamingSqlExecutionTime(
SimulatedExecutionTime.ofMinimumAndRandomTime(EXECUTION_TIME_SLOW_STATEMENT, 0));
- ExecutorService executor = Executors.newSingleThreadExecutor();
try (Connection connection = createConnection()) {
connection.setReadOnly(true);
connection.setAutocommit(false);
- executor.execute(
- () -> {
- waitForRequestsToContain(ExecuteSqlRequest.class);
- connection.cancel();
- });
+ ExecutorService executor = Executors.newSingleThreadExecutor();
try {
- connection.executeQuery(SELECT_RANDOM_STATEMENT);
- fail("Missing expected exception");
- } catch (SpannerException ex) {
- assertEquals(ErrorCode.CANCELLED, ex.getErrorCode());
+ executor.execute(
+ () -> {
+ waitForRequestsToContain(ExecuteSqlRequest.class);
+ connection.cancel();
+ });
+ SpannerException e =
+ assertThrows(
+ SpannerException.class, () -> connection.executeQuery(SELECT_RANDOM_STATEMENT));
+ assertEquals(ErrorCode.CANCELLED, e.getErrorCode());
+ } finally {
+ executor.shutdownNow();
}
- } finally {
- executor.shutdown();
}
}
@@ -700,35 +690,35 @@ public void testCancelReadOnlyTransactionalMultipleStatements() {
mockSpanner.setExecuteStreamingSqlExecutionTime(
SimulatedExecutionTime.ofMinimumAndRandomTime(EXECUTION_TIME_SLOW_STATEMENT, 0));
- ExecutorService executor = Executors.newSingleThreadExecutor();
try (Connection connection = createConnection()) {
connection.setReadOnly(true);
connection.setAutocommit(false);
- executor.execute(
- () -> {
- waitForRequestsToContain(ExecuteSqlRequest.class);
- connection.cancel();
- });
+ ExecutorService executor = Executors.newSingleThreadExecutor();
try {
- connection.executeQuery(Statement.of(SLOW_SELECT));
- fail("Missing expected exception");
- } catch (SpannerException e) {
+ executor.execute(
+ () -> {
+ waitForRequestsToContain(ExecuteSqlRequest.class);
+ connection.cancel();
+ });
+ SpannerException e =
+ assertThrows(
+ SpannerException.class, () -> connection.executeQuery(Statement.of(SLOW_SELECT)));
assertEquals(ErrorCode.CANCELLED, e.getErrorCode());
- }
- // try to do a new query that is fast.
- mockSpanner.removeAllExecutionTimes();
- connection.setStatementTimeout(TIMEOUT_FOR_FAST_STATEMENTS, TimeUnit.MILLISECONDS);
- try (ResultSet rs = connection.executeQuery(SELECT_RANDOM_STATEMENT)) {
- assertThat(rs, is(notNullValue()));
- }
- // rollback and do another fast query
- connection.rollback();
- try (ResultSet rs = connection.executeQuery(SELECT_RANDOM_STATEMENT)) {
- assertThat(rs, is(notNullValue()));
+ // try to do a new query that is fast.
+ mockSpanner.removeAllExecutionTimes();
+ connection.setStatementTimeout(TIMEOUT_FOR_FAST_STATEMENTS, TimeUnit.MILLISECONDS);
+ try (ResultSet rs = connection.executeQuery(SELECT_RANDOM_STATEMENT)) {
+ assertNotNull(rs);
+ }
+ // rollback and do another fast query
+ connection.rollback();
+ try (ResultSet rs = connection.executeQuery(SELECT_RANDOM_STATEMENT)) {
+ assertNotNull(rs);
+ }
+ } finally {
+ executor.shutdownNow();
}
- } finally {
- executor.shutdown();
}
}
@@ -737,22 +727,22 @@ public void testCancelReadWriteAutocommit() {
mockSpanner.setExecuteStreamingSqlExecutionTime(
SimulatedExecutionTime.ofMinimumAndRandomTime(EXECUTION_TIME_SLOW_STATEMENT, 0));
- ExecutorService executor = Executors.newSingleThreadExecutor();
try (Connection connection = createConnection()) {
connection.setAutocommit(true);
- executor.execute(
- () -> {
- waitForRequestsToContain(ExecuteSqlRequest.class);
- connection.cancel();
- });
+ ExecutorService executor = Executors.newSingleThreadExecutor();
try {
- connection.executeQuery(SELECT_RANDOM_STATEMENT);
- fail("Missing expected exception");
- } catch (SpannerException ex) {
- assertEquals(ErrorCode.CANCELLED, ex.getErrorCode());
+ executor.execute(
+ () -> {
+ waitForRequestsToContain(ExecuteSqlRequest.class);
+ connection.cancel();
+ });
+ SpannerException e =
+ assertThrows(
+ SpannerException.class, () -> connection.executeQuery(SELECT_RANDOM_STATEMENT));
+ assertEquals(ErrorCode.CANCELLED, e.getErrorCode());
+ } finally {
+ executor.shutdownNow();
}
- } finally {
- executor.shutdown();
}
}
@@ -761,29 +751,29 @@ public void testCancelReadWriteAutocommitMultipleStatements() {
mockSpanner.setExecuteStreamingSqlExecutionTime(
SimulatedExecutionTime.ofMinimumAndRandomTime(EXECUTION_TIME_SLOW_STATEMENT, 0));
- ExecutorService executor = Executors.newSingleThreadExecutor();
try (Connection connection = createConnection()) {
connection.setAutocommit(true);
- executor.execute(
- () -> {
- waitForRequestsToContain(ExecuteSqlRequest.class);
- connection.cancel();
- });
+ ExecutorService executor = Executors.newSingleThreadExecutor();
try {
- connection.executeQuery(SELECT_RANDOM_STATEMENT);
- fail("Missing expected exception");
- } catch (SpannerException ex) {
- assertEquals(ErrorCode.CANCELLED, ex.getErrorCode());
- }
+ executor.execute(
+ () -> {
+ waitForRequestsToContain(ExecuteSqlRequest.class);
+ connection.cancel();
+ });
+ SpannerException e =
+ assertThrows(
+ SpannerException.class, () -> connection.executeQuery(SELECT_RANDOM_STATEMENT));
+ assertEquals(ErrorCode.CANCELLED, e.getErrorCode());
- // try to do a new query that is fast.
- mockSpanner.removeAllExecutionTimes();
- connection.setStatementTimeout(TIMEOUT_FOR_FAST_STATEMENTS, TimeUnit.MILLISECONDS);
- try (ResultSet rs = connection.executeQuery(SELECT_RANDOM_STATEMENT)) {
- assertThat(rs, is(notNullValue()));
+ // try to do a new query that is fast.
+ mockSpanner.removeAllExecutionTimes();
+ connection.setStatementTimeout(TIMEOUT_FOR_FAST_STATEMENTS, TimeUnit.MILLISECONDS);
+ try (ResultSet rs = connection.executeQuery(SELECT_RANDOM_STATEMENT)) {
+ assertNotNull(rs);
+ }
+ } finally {
+ executor.shutdownNow();
}
- } finally {
- executor.shutdown();
}
}
@@ -792,22 +782,21 @@ public void testCancelReadWriteAutocommitSlowUpdate() {
mockSpanner.setExecuteSqlExecutionTime(
SimulatedExecutionTime.ofMinimumAndRandomTime(EXECUTION_TIME_SLOW_STATEMENT, 0));
- ExecutorService executor = Executors.newSingleThreadExecutor();
try (Connection connection = createConnection()) {
connection.setAutocommit(true);
- executor.execute(
- () -> {
- waitForRequestsToContain(ExecuteSqlRequest.class);
- connection.cancel();
- });
+ ExecutorService executor = Executors.newSingleThreadExecutor();
try {
- connection.execute(INSERT_STATEMENT);
- fail("Missing expected exception");
- } catch (SpannerException ex) {
- assertEquals(ErrorCode.CANCELLED, ex.getErrorCode());
+ executor.execute(
+ () -> {
+ waitForRequestsToContain(ExecuteSqlRequest.class);
+ connection.cancel();
+ });
+ SpannerException e =
+ assertThrows(SpannerException.class, () -> connection.execute(INSERT_STATEMENT));
+ assertEquals(ErrorCode.CANCELLED, e.getErrorCode());
+ } finally {
+ executor.shutdownNow();
}
- } finally {
- executor.shutdown();
}
}
@@ -816,20 +805,21 @@ public void testCancelReadWriteAutocommitSlowCommit() {
mockSpanner.setCommitExecutionTime(
SimulatedExecutionTime.ofMinimumAndRandomTime(EXECUTION_TIME_SLOW_STATEMENT, 0));
- ExecutorService executor = Executors.newSingleThreadExecutor();
try (Connection connection = createConnection()) {
connection.setAutocommit(true);
- executor.execute(
- () -> {
- waitForRequestsToContain(CommitRequest.class);
- connection.cancel();
- });
- connection.execute(INSERT_STATEMENT);
- fail("Missing expected exception");
- } catch (SpannerException ex) {
- assertEquals(ErrorCode.CANCELLED, ex.getErrorCode());
- } finally {
- executor.shutdown();
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ try {
+ executor.execute(
+ () -> {
+ waitForRequestsToContain(CommitRequest.class);
+ connection.cancel();
+ });
+ SpannerException e =
+ assertThrows(SpannerException.class, () -> connection.execute(INSERT_STATEMENT));
+ assertEquals(ErrorCode.CANCELLED, e.getErrorCode());
+ } finally {
+ executor.shutdownNow();
+ }
}
}
@@ -838,20 +828,22 @@ public void testCancelReadWriteTransactional() {
mockSpanner.setExecuteStreamingSqlExecutionTime(
SimulatedExecutionTime.ofMinimumAndRandomTime(EXECUTION_TIME_SLOW_STATEMENT, 0));
- ExecutorService executor = Executors.newSingleThreadExecutor();
try (Connection connection = createConnection()) {
connection.setAutocommit(false);
- executor.execute(
- () -> {
- waitForRequestsToContain(ExecuteSqlRequest.class);
- connection.cancel();
- });
- connection.executeQuery(SELECT_RANDOM_STATEMENT);
- fail("Missing expected exception");
- } catch (SpannerException ex) {
- assertEquals(ErrorCode.CANCELLED, ex.getErrorCode());
- } finally {
- executor.shutdown();
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ try {
+ executor.execute(
+ () -> {
+ waitForRequestsToContain(ExecuteSqlRequest.class);
+ connection.cancel();
+ });
+ SpannerException e =
+ assertThrows(
+ SpannerException.class, () -> connection.executeQuery(SELECT_RANDOM_STATEMENT));
+ assertEquals(ErrorCode.CANCELLED, e.getErrorCode());
+ } finally {
+ executor.shutdownNow();
+ }
}
}
@@ -860,31 +852,31 @@ public void testCancelReadWriteTransactionalMultipleStatements() {
mockSpanner.setExecuteStreamingSqlExecutionTime(
SimulatedExecutionTime.ofMinimumAndRandomTime(EXECUTION_TIME_SLOW_STATEMENT, 0));
- ExecutorService executor = Executors.newSingleThreadExecutor();
try (Connection connection = createConnection()) {
connection.setAutocommit(false);
- executor.execute(
- () -> {
- waitForRequestsToContain(ExecuteSqlRequest.class);
- connection.cancel();
- });
+ ExecutorService executor = Executors.newSingleThreadExecutor();
try {
- connection.executeQuery(SELECT_RANDOM_STATEMENT);
- fail("Missing expected exception");
- } catch (SpannerException e) {
+ executor.execute(
+ () -> {
+ waitForRequestsToContain(ExecuteSqlRequest.class);
+ connection.cancel();
+ });
+ SpannerException e =
+ assertThrows(
+ SpannerException.class, () -> connection.executeQuery(SELECT_RANDOM_STATEMENT));
assertEquals(ErrorCode.CANCELLED, e.getErrorCode());
+ // Rollback the transaction as it is no longer usable.
+ connection.rollback();
+
+ // Try to do a new query that is fast.
+ mockSpanner.removeAllExecutionTimes();
+ connection.setStatementTimeout(TIMEOUT_FOR_FAST_STATEMENTS, TimeUnit.MILLISECONDS);
+ try (ResultSet rs = connection.executeQuery(SELECT_RANDOM_STATEMENT)) {
+ assertNotNull(rs);
+ }
+ } finally {
+ executor.shutdownNow();
}
- // Rollback the transaction as it is no longer usable.
- connection.rollback();
-
- // Try to do a new query that is fast.
- mockSpanner.removeAllExecutionTimes();
- connection.setStatementTimeout(TIMEOUT_FOR_FAST_STATEMENTS, TimeUnit.MILLISECONDS);
- try (ResultSet rs = connection.executeQuery(SELECT_RANDOM_STATEMENT)) {
- assertThat(rs, is(notNullValue()));
- }
- } finally {
- executor.shutdown();
}
}
@@ -925,22 +917,22 @@ static void addMockDdlOperations(int count, boolean done) {
public void testCancelDdlBatch() {
addSlowMockDdlOperation();
- ExecutorService executor = Executors.newSingleThreadExecutor();
try (Connection connection = createConnection()) {
connection.setAutocommit(false);
connection.startBatchDdl();
connection.execute(Statement.of(SLOW_DDL));
- executor.execute(
- () -> {
- Uninterruptibles.sleepUninterruptibly(100L, TimeUnit.MILLISECONDS);
- connection.cancel();
- });
- connection.runBatch();
- fail("Missing expected exception");
- } catch (SpannerException ex) {
- assertEquals(ErrorCode.CANCELLED, ex.getErrorCode());
- } finally {
- executor.shutdown();
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ try {
+ executor.execute(
+ () -> {
+ waitForDdlRequestOnServer();
+ connection.cancel();
+ });
+ SpannerException e = assertThrows(SpannerException.class, () -> connection.runBatch());
+ assertEquals(ErrorCode.CANCELLED, e.getErrorCode());
+ } finally {
+ executor.shutdownNow();
+ }
}
}
@@ -948,20 +940,21 @@ public void testCancelDdlBatch() {
public void testCancelDdlAutocommit() {
addSlowMockDdlOperation();
- ExecutorService executor = Executors.newSingleThreadExecutor();
try (Connection connection = createConnection()) {
connection.setAutocommit(true);
- executor.execute(
- () -> {
- Uninterruptibles.sleepUninterruptibly(100L, TimeUnit.MILLISECONDS);
- connection.cancel();
- });
- connection.execute(Statement.of(SLOW_DDL));
- fail("Missing expected exception");
- } catch (SpannerException ex) {
- assertEquals(ErrorCode.CANCELLED, ex.getErrorCode());
- } finally {
- executor.shutdown();
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ try {
+ executor.execute(
+ () -> {
+ waitForDdlRequestOnServer();
+ connection.cancel();
+ });
+ SpannerException e =
+ assertThrows(SpannerException.class, () -> connection.execute(Statement.of(SLOW_DDL)));
+ assertEquals(ErrorCode.CANCELLED, e.getErrorCode());
+ } finally {
+ executor.shutdownNow();
+ }
}
}
@@ -972,10 +965,9 @@ public void testTimeoutExceptionDdlAutocommit() {
try (Connection connection = createConnection()) {
connection.setAutocommit(true);
connection.setStatementTimeout(TIMEOUT_FOR_SLOW_STATEMENTS, TimeUnit.MILLISECONDS);
- connection.execute(Statement.of(SLOW_DDL));
- fail("Missing expected exception");
- } catch (SpannerException ex) {
- assertEquals(ErrorCode.DEADLINE_EXCEEDED, ex.getErrorCode());
+ SpannerException e =
+ assertThrows(SpannerException.class, () -> connection.execute(Statement.of(SLOW_DDL)));
+ assertEquals(ErrorCode.DEADLINE_EXCEEDED, e.getErrorCode());
}
}
@@ -989,18 +981,15 @@ public void testTimeoutExceptionDdlAutocommitMultipleStatements() {
// assert that multiple statements after each other also time out
for (int i = 0; i < 2; i++) {
- try {
- connection.execute(Statement.of(SLOW_DDL));
- fail("Missing expected exception");
- } catch (SpannerException e) {
- assertEquals(ErrorCode.DEADLINE_EXCEEDED, e.getErrorCode());
- }
+ SpannerException e =
+ assertThrows(SpannerException.class, () -> connection.execute(Statement.of(SLOW_DDL)));
+ assertEquals(ErrorCode.DEADLINE_EXCEEDED, e.getErrorCode());
}
// try to do a new DDL statement that is fast.
mockDatabaseAdmin.reset();
addFastMockDdlOperation();
connection.setStatementTimeout(TIMEOUT_FOR_FAST_STATEMENTS, TimeUnit.MILLISECONDS);
- assertThat(connection.execute(Statement.of(FAST_DDL)), is(notNullValue()));
+ assertNotNull(connection.execute(Statement.of(FAST_DDL)));
}
}
@@ -1016,10 +1005,8 @@ public void testTimeoutExceptionDdlBatch() {
// the following statement will NOT timeout as the statement is only buffered locally
connection.execute(Statement.of(SLOW_DDL));
// the runBatch() statement sends the statement to the server and should timeout
- connection.runBatch();
- fail("Missing expected exception");
- } catch (SpannerException ex) {
- assertEquals(ErrorCode.DEADLINE_EXCEEDED, ex.getErrorCode());
+ SpannerException e = assertThrows(SpannerException.class, () -> connection.runBatch());
+ assertEquals(ErrorCode.DEADLINE_EXCEEDED, e.getErrorCode());
}
}
@@ -1033,22 +1020,17 @@ public void testTimeoutExceptionDdlBatchMultipleStatements() {
// assert that multiple statements after each other also time out
for (int i = 0; i < 2; i++) {
-
connection.startBatchDdl();
connection.execute(Statement.of(SLOW_DDL));
- try {
- connection.runBatch();
- fail("Missing expected exception");
- } catch (SpannerException e) {
- assertEquals(ErrorCode.DEADLINE_EXCEEDED, e.getErrorCode());
- }
+ SpannerException e = assertThrows(SpannerException.class, () -> connection.runBatch());
+ assertEquals(ErrorCode.DEADLINE_EXCEEDED, e.getErrorCode());
}
// try to do a new DDL statement that is fast.
mockDatabaseAdmin.reset();
addFastMockDdlOperation();
connection.setStatementTimeout(TIMEOUT_FOR_FAST_STATEMENTS, TimeUnit.MILLISECONDS);
connection.startBatchDdl();
- assertThat(connection.execute(Statement.of(FAST_DDL)), is(notNullValue()));
+ assertNotNull(connection.execute(Statement.of(FAST_DDL)));
connection.runBatch();
}
}
@@ -1061,13 +1043,9 @@ public void testTimeoutDifferentTimeUnits() {
try (Connection connection = createConnection()) {
connection.setAutocommit(true);
for (TimeUnit unit : ReadOnlyStalenessUtil.SUPPORTED_UNITS) {
+ // Only set the timeout, don't execute a statement with the timeout to prevent unnecessarily
+ // slowing down the build time.
connection.setStatementTimeout(1L, unit);
- try {
- connection.execute(SELECT_RANDOM_STATEMENT);
- fail("Missing expected exception");
- } catch (SpannerException e) {
- assertEquals(ErrorCode.DEADLINE_EXCEEDED, e.getErrorCode());
- }
}
}
}
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITDdlTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITDdlTest.java
index 8448c601b1..74c072cd76 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITDdlTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITDdlTest.java
@@ -32,6 +32,6 @@ public class ITDdlTest extends ITAbstractSpannerTest {
@Test
public void testSqlScript() throws Exception {
SqlScriptVerifier verifier = new SqlScriptVerifier(new ITConnectionProvider());
- verifier.verifyStatementsInFile("ITDdlTest.sql", SqlScriptVerifier.class);
+ verifier.verifyStatementsInFile("ITDdlTest.sql", SqlScriptVerifier.class, false);
}
}
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITReadOnlySpannerTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITReadOnlySpannerTest.java
index 55a4926f64..fd5df07954 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITReadOnlySpannerTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITReadOnlySpannerTest.java
@@ -66,7 +66,7 @@ public void createTestTables() throws Exception {
// create tables
SqlScriptVerifier verifier = new SqlScriptVerifier(new ITConnectionProvider());
verifier.verifyStatementsInFile(
- "ITReadOnlySpannerTest_CreateTables.sql", SqlScriptVerifier.class);
+ "ITReadOnlySpannerTest_CreateTables.sql", SqlScriptVerifier.class, false);
// fill tables with data
connection.setAutocommit(false);
@@ -101,7 +101,7 @@ public void testSqlScript() throws Exception {
// Wait 100ms to ensure that staleness tests in the script succeed.
Thread.sleep(100L);
SqlScriptVerifier verifier = new SqlScriptVerifier(new ITConnectionProvider());
- verifier.verifyStatementsInFile("ITReadOnlySpannerTest.sql", SqlScriptVerifier.class);
+ verifier.verifyStatementsInFile("ITReadOnlySpannerTest.sql", SqlScriptVerifier.class, false);
}
@Test
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITReadWriteAutocommitSpannerTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITReadWriteAutocommitSpannerTest.java
index ab1da50992..d394013fbe 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITReadWriteAutocommitSpannerTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITReadWriteAutocommitSpannerTest.java
@@ -59,7 +59,7 @@ public boolean doCreateDefaultTestTable() {
public void test01_SqlScript() throws Exception {
SqlScriptVerifier verifier = new SqlScriptVerifier(new ITConnectionProvider());
verifier.verifyStatementsInFile(
- "ITReadWriteAutocommitSpannerTest.sql", SqlScriptVerifier.class);
+ "ITReadWriteAutocommitSpannerTest.sql", SqlScriptVerifier.class, false);
}
@Test
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITSqlMusicScriptTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITSqlMusicScriptTest.java
index e8a479c6d6..e7afe95770 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITSqlMusicScriptTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITSqlMusicScriptTest.java
@@ -54,7 +54,7 @@ public class ITSqlMusicScriptTest extends ITAbstractSpannerTest {
public void test01_RunScript() throws Exception {
SqlScriptVerifier verifier = new SqlScriptVerifier();
try (GenericConnection connection = SpannerGenericConnection.of(createConnection())) {
- verifier.verifyStatementsInFile(connection, SCRIPT_FILE, SqlScriptVerifier.class);
+ verifier.verifyStatementsInFile(connection, SCRIPT_FILE, SqlScriptVerifier.class, false);
}
}
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITSqlScriptTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITSqlScriptTest.java
index 5a1e9bb628..026495605e 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITSqlScriptTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITSqlScriptTest.java
@@ -66,7 +66,10 @@ public class ITSqlScriptTest extends ITAbstractSpannerTest {
public void test01_CreateTables() throws Exception {
try (ITConnection connection = createConnection()) {
verifier.verifyStatementsInFile(
- SpannerGenericConnection.of(connection), CREATE_TABLES_FILE, SqlScriptVerifier.class);
+ SpannerGenericConnection.of(connection),
+ CREATE_TABLES_FILE,
+ SqlScriptVerifier.class,
+ false);
}
}
@@ -76,7 +79,8 @@ public void test02_InsertTestData() throws Exception {
verifier.verifyStatementsInFile(
SpannerGenericConnection.of(connection),
INSERT_AND_VERIFY_TEST_DATA,
- SqlScriptVerifier.class);
+ SqlScriptVerifier.class,
+ false);
} catch (SpannerException e) {
if (isUsingEmulator() && e.getErrorCode() == ErrorCode.ALREADY_EXISTS) {
// Errors in a transaction are 'sticky' on the emulator, so any query in the same
@@ -92,7 +96,8 @@ public void test03_TestGetReadTimestamp() throws Exception {
verifier.verifyStatementsInFile(
SpannerGenericConnection.of(connection),
TEST_GET_READ_TIMESTAMP,
- SqlScriptVerifier.class);
+ SqlScriptVerifier.class,
+ false);
}
}
@@ -102,7 +107,8 @@ public void test04_TestGetCommitTimestamp() throws Exception {
verifier.verifyStatementsInFile(
SpannerGenericConnection.of(connection),
TEST_GET_COMMIT_TIMESTAMP,
- SqlScriptVerifier.class);
+ SqlScriptVerifier.class,
+ false);
} catch (SpannerException e) {
if (isUsingEmulator() && e.getErrorCode() == ErrorCode.INVALID_ARGUMENT) {
// Errors in a transaction are 'sticky' on the emulator, so any query in the same
@@ -117,7 +123,8 @@ public void test05_TestTemporaryTransactions() throws Exception {
verifier.verifyStatementsInFile(
SpannerGenericConnection.of(connection),
TEST_TEMPORARY_TRANSACTIONS,
- SqlScriptVerifier.class);
+ SqlScriptVerifier.class,
+ false);
}
}
@@ -125,7 +132,10 @@ public void test05_TestTemporaryTransactions() throws Exception {
public void test06_TestTransactionMode() throws Exception {
try (ITConnection connection = createConnection()) {
verifier.verifyStatementsInFile(
- SpannerGenericConnection.of(connection), TEST_TRANSACTION_MODE, SqlScriptVerifier.class);
+ SpannerGenericConnection.of(connection),
+ TEST_TRANSACTION_MODE,
+ SqlScriptVerifier.class,
+ false);
}
}
@@ -135,7 +145,8 @@ public void test07_TestTransactionModeReadOnly() throws Exception {
verifier.verifyStatementsInFile(
SpannerGenericConnection.of(connection),
TEST_TRANSACTION_MODE_READ_ONLY,
- SqlScriptVerifier.class);
+ SqlScriptVerifier.class,
+ false);
}
}
@@ -145,7 +156,8 @@ public void test08_TestReadOnlyStaleness() throws Exception {
verifier.verifyStatementsInFile(
SpannerGenericConnection.of(connection),
TEST_READ_ONLY_STALENESS,
- SqlScriptVerifier.class);
+ SqlScriptVerifier.class,
+ false);
}
}
@@ -155,7 +167,8 @@ public void test09_TestAutocommitDmlMode() throws Exception {
verifier.verifyStatementsInFile(
SpannerGenericConnection.of(connection),
TEST_AUTOCOMMIT_DML_MODE,
- SqlScriptVerifier.class);
+ SqlScriptVerifier.class,
+ false);
}
}
@@ -165,7 +178,8 @@ public void test10_TestAutocommitReadOnly() throws Exception {
verifier.verifyStatementsInFile(
SpannerGenericConnection.of(connection),
TEST_AUTOCOMMIT_READ_ONLY,
- SqlScriptVerifier.class);
+ SqlScriptVerifier.class,
+ false);
}
}
@@ -173,7 +187,10 @@ public void test10_TestAutocommitReadOnly() throws Exception {
public void test11_TestStatementTimeout() throws Exception {
try (ITConnection connection = createConnection()) {
verifier.verifyStatementsInFile(
- SpannerGenericConnection.of(connection), TEST_STATEMENT_TIMEOUT, SqlScriptVerifier.class);
+ SpannerGenericConnection.of(connection),
+ TEST_STATEMENT_TIMEOUT,
+ SqlScriptVerifier.class,
+ false);
}
}
@@ -181,7 +198,10 @@ public void test11_TestStatementTimeout() throws Exception {
public void test12_TestSetStatements() throws Exception {
try (ITConnection connection = createConnection()) {
verifier.verifyStatementsInFile(
- SpannerGenericConnection.of(connection), TEST_SET_STATEMENTS, SqlScriptVerifier.class);
+ SpannerGenericConnection.of(connection),
+ TEST_SET_STATEMENTS,
+ SqlScriptVerifier.class,
+ false);
}
}
@@ -191,7 +211,8 @@ public void test13_TestInvalidStatements() throws Exception {
verifier.verifyStatementsInFile(
SpannerGenericConnection.of(connection),
TEST_INVALID_STATEMENTS,
- SqlScriptVerifier.class);
+ SqlScriptVerifier.class,
+ false);
}
}
}
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITTransactionModeTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITTransactionModeTest.java
index 3874f595ba..33b059c8bf 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITTransactionModeTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITTransactionModeTest.java
@@ -53,7 +53,7 @@ public boolean doCreateDefaultTestTable() {
@Test
public void testSqlScript() throws Exception {
SqlScriptVerifier verifier = new SqlScriptVerifier(new ITConnectionProvider());
- verifier.verifyStatementsInFile("ITTransactionModeTest.sql", SqlScriptVerifier.class);
+ verifier.verifyStatementsInFile("ITTransactionModeTest.sql", SqlScriptVerifier.class, false);
}
@Test
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpcTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpcTest.java
index 39e16fcca4..a004dd3465 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpcTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpcTest.java
@@ -20,7 +20,8 @@
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.fail;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
import static org.junit.Assume.assumeTrue;
import com.google.api.gax.core.GaxProperties;
@@ -84,7 +85,7 @@
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import org.junit.After;
-import org.junit.Before;
+import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -141,24 +142,22 @@ public class GapicSpannerRpcTest {
new java.util.Date(
System.currentTimeMillis() + TimeUnit.MILLISECONDS.convert(1L, TimeUnit.DAYS))));
- private MockSpannerServiceImpl mockSpanner;
- private MockInstanceAdminImpl mockInstanceAdmin;
- private MockDatabaseAdminImpl mockDatabaseAdmin;
- private Server server;
- private InetSocketAddress address;
- private final Map optionsMap = new HashMap<>();
- private Metadata seenHeaders;
- private String defaultUserAgent;
+ private static MockSpannerServiceImpl mockSpanner;
+ private static MockInstanceAdminImpl mockInstanceAdmin;
+ private static MockDatabaseAdminImpl mockDatabaseAdmin;
+ private static Server server;
+ private static InetSocketAddress address;
+ private static final Map optionsMap = new HashMap<>();
+ private static Metadata lastSeenHeaders;
+ private static String defaultUserAgent;
+ private static Spanner spanner;
@BeforeClass
- public static void checkNotEmulator() {
+ public static void startServer() throws IOException {
assumeTrue(
"Skip tests when emulator is enabled as this test interferes with the check whether the emulator is running",
System.getenv("SPANNER_EMULATOR_HOST") == null);
- }
- @Before
- public void startServer() throws IOException {
defaultUserAgent = "spanner-java/" + GaxProperties.getLibraryVersion(GapicSpannerRpc.class);
mockSpanner = new MockSpannerServiceImpl();
mockSpanner.setAbortProbability(0.0D); // We don't want any unpredictable aborted transactions.
@@ -182,7 +181,7 @@ public ServerCall.Listener interceptCall(
ServerCall call,
Metadata headers,
ServerCallHandler next) {
- seenHeaders = headers;
+ lastSeenHeaders = headers;
String auth =
headers.get(Key.of("authorization", Metadata.ASCII_STRING_MARSHALLER));
assertThat(auth).isEqualTo("Bearer " + VARIABLE_OAUTH_TOKEN);
@@ -192,12 +191,21 @@ public ServerCall.Listener interceptCall(
.build()
.start();
optionsMap.put(Option.CHANNEL_HINT, 1L);
+ spanner = createSpannerOptions().getService();
+ }
+
+ @AfterClass
+ public static void stopServer() throws InterruptedException {
+ if (spanner != null) {
+ spanner.close();
+ server.shutdown();
+ server.awaitTermination();
+ }
}
@After
- public void stopServer() throws InterruptedException {
- server.shutdown();
- server.awaitTermination();
+ public void reset() {
+ mockSpanner.reset();
}
private static final int NUMBER_OF_TEST_RUNS = 2;
@@ -207,8 +215,8 @@ public void stopServer() throws InterruptedException {
@Test
public void testCloseAllThreadsWhenClosingSpanner() throws InterruptedException {
+ int initialNumberOfThreads = getNumberOfThreadsWithName(SPANNER_THREAD_NAME, false, 0);
for (int i = 0; i < NUMBER_OF_TEST_RUNS; i++) {
- assertThat(getNumberOfThreadsWithName(SPANNER_THREAD_NAME, true), is(equalTo(0)));
// Create Spanner instance.
SpannerOptions options = createSpannerOptions();
Spanner spanner = options.getService();
@@ -227,8 +235,8 @@ public void testCloseAllThreadsWhenClosingSpanner() throws InterruptedException
// sessions should initialize multiple transport channels.
resultSets.add(rs);
// Check whether the number of expected threads has been reached.
- if (getNumberOfThreadsWithName(SPANNER_THREAD_NAME, false)
- == options.getNumChannels() * NUM_THREADS_PER_CHANNEL) {
+ if (getNumberOfThreadsWithName(SPANNER_THREAD_NAME, false, initialNumberOfThreads)
+ == options.getNumChannels() * NUM_THREADS_PER_CHANNEL + initialNumberOfThreads) {
break;
}
}
@@ -253,11 +261,14 @@ public void testCloseAllThreadsWhenClosingSpanner() throws InterruptedException
spanner.close();
// Wait for up to two seconds to allow the threads to actually shutdown.
Stopwatch watch = Stopwatch.createStarted();
- while (getNumberOfThreadsWithName(SPANNER_THREAD_NAME, false) > 0
+ while (getNumberOfThreadsWithName(SPANNER_THREAD_NAME, false, initialNumberOfThreads)
+ > initialNumberOfThreads
&& watch.elapsed(TimeUnit.SECONDS) < 2) {
Thread.sleep(10L);
}
- assertThat(getNumberOfThreadsWithName(SPANNER_THREAD_NAME, true), is(equalTo(0)));
+ assertThat(
+ getNumberOfThreadsWithName(SPANNER_THREAD_NAME, true, initialNumberOfThreads),
+ is(equalTo(initialNumberOfThreads)));
}
}
@@ -268,7 +279,7 @@ public void testCloseAllThreadsWhenClosingSpanner() throws InterruptedException
@Test
public void testMultipleOpenSpanners() throws InterruptedException {
List spanners = new ArrayList<>();
- assertThat(getNumberOfThreadsWithName(SPANNER_THREAD_NAME, true), is(equalTo(0)));
+ int initialNumberOfThreads = getNumberOfThreadsWithName(SPANNER_THREAD_NAME, false, 0);
for (int openSpanners = 1; openSpanners <= 3; openSpanners++) {
// Create Spanner instance.
SpannerOptions options = createSpannerOptions();
@@ -282,8 +293,9 @@ public void testMultipleOpenSpanners() throws InterruptedException {
// to ensure we also hit multiple channels.
for (int sessionCount = 0;
sessionCount < options.getSessionPoolOptions().getMaxSessions()
- && getNumberOfThreadsWithName(SPANNER_THREAD_NAME, false)
- < options.getNumChannels() * NUM_THREADS_PER_CHANNEL * openSpanners;
+ && getNumberOfThreadsWithName(SPANNER_THREAD_NAME, false, initialNumberOfThreads)
+ < options.getNumChannels() * NUM_THREADS_PER_CHANNEL * openSpanners
+ + initialNumberOfThreads;
sessionCount++) {
ResultSet rs = client.singleUse().executeQuery(SELECT1AND2);
// Execute ResultSet#next() to send the query to Spanner.
@@ -302,11 +314,14 @@ && getNumberOfThreadsWithName(SPANNER_THREAD_NAME, false)
}
// Wait a little to allow the threads to actually shutdown.
Stopwatch watch = Stopwatch.createStarted();
- while (getNumberOfThreadsWithName(SPANNER_THREAD_NAME, false) > 0
+ while (getNumberOfThreadsWithName(SPANNER_THREAD_NAME, false, initialNumberOfThreads)
+ > initialNumberOfThreads
&& watch.elapsed(TimeUnit.SECONDS) < 2) {
Thread.sleep(10L);
}
- assertThat(getNumberOfThreadsWithName(SPANNER_THREAD_NAME, true), is(equalTo(0)));
+ assertThat(
+ getNumberOfThreadsWithName(SPANNER_THREAD_NAME, true, initialNumberOfThreads),
+ is(equalTo(initialNumberOfThreads)));
}
@Test
@@ -317,7 +332,7 @@ public void testCallCredentialsProviderPreferenceAboveCredentials() {
.setCredentials(STATIC_CREDENTIALS)
.setCallCredentialsProvider(() -> MoreCallCredentials.from(VARIABLE_CREDENTIALS))
.build();
- GapicSpannerRpc rpc = new GapicSpannerRpc(options);
+ GapicSpannerRpc rpc = new GapicSpannerRpc(options, false);
// GoogleAuthLibraryCallCredentials doesn't implement equals, so we can only check for the
// existence.
assertThat(
@@ -340,7 +355,7 @@ public void testCallCredentialsProviderReturnsNull() {
.setCredentials(STATIC_CREDENTIALS)
.setCallCredentialsProvider(() -> null)
.build();
- GapicSpannerRpc rpc = new GapicSpannerRpc(options);
+ GapicSpannerRpc rpc = new GapicSpannerRpc(options, false);
assertThat(
rpc.newCallContext(
optionsMap,
@@ -360,7 +375,7 @@ public void testNoCallCredentials() {
.setProjectId("some-project")
.setCredentials(STATIC_CREDENTIALS)
.build();
- GapicSpannerRpc rpc = new GapicSpannerRpc(options);
+ GapicSpannerRpc rpc = new GapicSpannerRpc(options, false);
assertThat(
rpc.newCallContext(
optionsMap,
@@ -403,41 +418,38 @@ public ApiCallContext configure(
};
mockSpanner.setExecuteSqlExecutionTime(SimulatedExecutionTime.ofMinimumAndRandomTime(10, 0));
- SpannerOptions options = createSpannerOptions();
- try (Spanner spanner = options.getService()) {
- final DatabaseClient client =
- spanner.getDatabaseClient(DatabaseId.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"));
- Context context =
- Context.current().withValue(SpannerOptions.CALL_CONTEXT_CONFIGURATOR_KEY, configurator);
- context.run(
- () -> {
- try {
- // First try with a 1ns timeout. This should always cause a DEADLINE_EXCEEDED
- // exception.
- timeoutHolder.timeout = Duration.ofNanos(1L);
+ final DatabaseClient client =
+ spanner.getDatabaseClient(DatabaseId.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"));
+ Context context =
+ Context.current().withValue(SpannerOptions.CALL_CONTEXT_CONFIGURATOR_KEY, configurator);
+ context.run(
+ () -> {
+ // First try with a 1ns timeout. This should always cause a DEADLINE_EXCEEDED
+ // exception.
+ timeoutHolder.timeout = Duration.ofNanos(1L);
+ SpannerException e =
+ assertThrows(
+ SpannerException.class,
+ () ->
+ client
+ .readWriteTransaction()
+ .run(transaction -> transaction.executeUpdate(UPDATE_FOO_STATEMENT)));
+ assertEquals(ErrorCode.DEADLINE_EXCEEDED, e.getErrorCode());
+
+ // Then try with a longer timeout. This should now succeed.
+ timeoutHolder.timeout = Duration.ofMinutes(1L);
+ long updateCount =
client
.readWriteTransaction()
.run(transaction -> transaction.executeUpdate(UPDATE_FOO_STATEMENT));
- fail("missing expected timeout exception");
- } catch (SpannerException e) {
- assertThat(e.getErrorCode()).isEqualTo(ErrorCode.DEADLINE_EXCEEDED);
- }
-
- // Then try with a longer timeout. This should now succeed.
- timeoutHolder.timeout = Duration.ofMinutes(1L);
- Long updateCount =
- client
- .readWriteTransaction()
- .run(transaction -> transaction.executeUpdate(UPDATE_FOO_STATEMENT));
- assertThat(updateCount).isEqualTo(1L);
- });
- }
+ assertEquals(1L, updateCount);
+ });
}
@Test
public void testNewCallContextWithNullRequestAndNullMethod() {
SpannerOptions options = SpannerOptions.newBuilder().setProjectId("some-project").build();
- GapicSpannerRpc rpc = new GapicSpannerRpc(options);
+ GapicSpannerRpc rpc = new GapicSpannerRpc(options, false);
assertThat(rpc.newCallContext(optionsMap, "/some/resource", null, null)).isNotNull();
rpc.shutdown();
}
@@ -477,18 +489,15 @@ public void testAdminRequestsLimitExceededRetryAlgorithm() {
@Test
public void testDefaultUserAgent() {
- final SpannerOptions options = createSpannerOptions();
- try (final Spanner spanner = options.getService()) {
- final DatabaseClient databaseClient =
- spanner.getDatabaseClient(DatabaseId.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"));
-
- try (final ResultSet rs = databaseClient.singleUse().executeQuery(SELECT1AND2)) {
- rs.next();
- }
+ final DatabaseClient databaseClient =
+ spanner.getDatabaseClient(DatabaseId.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"));
- assertThat(seenHeaders.get(Key.of("user-agent", Metadata.ASCII_STRING_MARSHALLER)))
- .contains(defaultUserAgent);
+ try (final ResultSet rs = databaseClient.singleUse().executeQuery(SELECT1AND2)) {
+ rs.next();
}
+
+ assertThat(lastSeenHeaders.get(Key.of("user-agent", Metadata.ASCII_STRING_MARSHALLER)))
+ .contains(defaultUserAgent);
}
@Test
@@ -510,13 +519,13 @@ public void testCustomUserAgent() {
rs.next();
}
- assertThat(seenHeaders.get(Key.of("user-agent", Metadata.ASCII_STRING_MARSHALLER)))
+ assertThat(lastSeenHeaders.get(Key.of("user-agent", Metadata.ASCII_STRING_MARSHALLER)))
.contains("test-agent " + defaultUserAgent);
}
}
}
- private SpannerOptions createSpannerOptions() {
+ private static SpannerOptions createSpannerOptions() {
String endpoint = address.getHostString() + ":" + server.getPort();
return SpannerOptions.newBuilder()
.setProjectId("[PROJECT]")
@@ -535,7 +544,7 @@ private SpannerOptions createSpannerOptions() {
.build();
}
- private int getNumberOfThreadsWithName(String serviceName, boolean dumpStack) {
+ private int getNumberOfThreadsWithName(String serviceName, boolean dumpStack, int expected) {
Pattern pattern = Pattern.compile(String.format(THREAD_PATTERN, serviceName));
ThreadGroup group = Thread.currentThread().getThreadGroup();
while (group.getParent() != null) {
@@ -544,14 +553,18 @@ private int getNumberOfThreadsWithName(String serviceName, boolean dumpStack) {
Thread[] threads = new Thread[100 * NUMBER_OF_TEST_RUNS];
int numberOfThreads = group.enumerate(threads);
int res = 0;
+ List found = new ArrayList<>();
for (int i = 0; i < numberOfThreads; i++) {
if (pattern.matcher(threads[i].getName()).matches()) {
if (dumpStack) {
- dumpThread(threads[i]);
+ found.add(threads[i]);
}
res++;
}
}
+ if (dumpStack && res > expected) {
+ found.stream().forEach(t -> dumpThread(t));
+ }
return res;
}
diff --git a/samples/README.md b/samples/README.md
index 6df90704ed..b65ad460b5 100644
--- a/samples/README.md
+++ b/samples/README.md
@@ -17,7 +17,7 @@ Install [Maven](http://maven.apache.org/).
Build your project from the root directory (`java-spanner`):
- mvn clean package -DskipTests -DskipUTs -Penable-samples
+ mvn clean package -DskipTests -Penable-samples
Every subsequent command here should be run from a subdirectory (`cd samples/snippets`).