public void CommandHasOptimizerVersionSetOnCommand()
        {
            Mock<SpannerClient> spannerClientMock = SpannerClientHelpers
                .CreateMockClient(Logger.DefaultLogger, MockBehavior.Strict);
            spannerClientMock
                .SetupBatchCreateSessionsAsync()
                .SetupExecuteStreamingSql();

            var cmdOptimizerVersion = "3";
            // Optimizer version set at a command level has higher precedence
            // than version set through the connection or the environment
            // variable.
            const string envOptimizerVersion = "2";
            RunActionWithEnvOptimizerVersion(() =>
            {
                const string connOptimizerVersion = "1";
                SpannerConnection connection = BuildSpannerConnection(spannerClientMock);
                var queryOptions = QueryOptions.Empty.WithOptimizerVersion(connOptimizerVersion);
                connection.QueryOptions = queryOptions;

                var command = connection.CreateSelectCommand("SELECT * FROM FOO");
                command.QueryOptions = QueryOptions.Empty.WithOptimizerVersion(cmdOptimizerVersion);
                using (var reader = command.ExecuteReader())
                {
                    Assert.True(reader.HasRows);
                }
            }, envOptimizerVersion);

            spannerClientMock.Verify(client => client.ExecuteStreamingSql(
                It.Is<ExecuteSqlRequest>(request => request.QueryOptions.OptimizerVersion == cmdOptimizerVersion),
                It.IsAny<CallSettings>()), Times.Once());
        }
        public void CommandIncludesRequestAndTransactionTag()
        {
            var requestTag     = "request-tag-1";
            var transactionTag = "transaction-tag-1";
            Mock <SpannerClient> spannerClientMock = SpannerClientHelpers
                                                     .CreateMockClient(Logger.DefaultLogger, MockBehavior.Strict);

            spannerClientMock
            .SetupBatchCreateSessionsAsync()
            .SetupBeginTransactionAsync()
            .SetupExecuteBatchDmlAsync()
            .SetupCommitAsync();
            SpannerConnection  connection  = SpannerCommandTests.BuildSpannerConnection(spannerClientMock);
            SpannerTransaction transaction = connection.BeginTransaction();

            transaction.Tag = transactionTag;

            var command = transaction.CreateBatchDmlCommand();

            command.Add("UPDATE FOO SET BAR=1 WHERE TRUE");
            command.Tag = requestTag;
            command.ExecuteNonQuery();
            transaction.Commit();

            spannerClientMock.Verify(client => client.ExecuteBatchDmlAsync(
                                         It.Is <ExecuteBatchDmlRequest>(request => request.RequestOptions.RequestTag == requestTag && request.RequestOptions.TransactionTag == transactionTag),
                                         It.IsAny <CallSettings>()), Times.Once());
            spannerClientMock.Verify(client => client.CommitAsync(
                                         It.Is <CommitRequest>(request => request.RequestOptions.RequestTag == "" && request.RequestOptions.TransactionTag == transactionTag),
                                         It.IsAny <CallSettings>()), Times.Once());
        }
        public void CommitIncludesPriority()
        {
            var commitPriority  = Priority.Medium;
            var commandPriority = Priority.High;
            Mock <SpannerClient> spannerClientMock = SpannerClientHelpers
                                                     .CreateMockClient(Logger.DefaultLogger, MockBehavior.Strict);

            spannerClientMock
            .SetupBatchCreateSessionsAsync()
            .SetupBeginTransactionAsync()
            .SetupExecuteStreamingSql()
            .SetupCommitAsync();
            SpannerConnection  connection  = BuildSpannerConnection(spannerClientMock);
            SpannerTransaction transaction = connection.BeginTransaction();

            transaction.CommitPriority = commitPriority;

            var command = connection.CreateSelectCommand("SELECT * FROM FOO");

            command.Transaction = transaction;
            command.Priority    = commandPriority;
            using (var reader = command.ExecuteReader())
            {
                Assert.True(reader.HasRows);
            }
            transaction.Commit();

            spannerClientMock.Verify(client => client.ExecuteStreamingSql(
                                         It.Is <ExecuteSqlRequest>(request => request.RequestOptions.Priority == PriorityConverter.ToProto(commandPriority)),
                                         It.IsAny <CallSettings>()), Times.Once());
            spannerClientMock.Verify(client => client.CommitAsync(
                                         It.Is <CommitRequest>(request => request.RequestOptions.Priority == PriorityConverter.ToProto(commitPriority)),
                                         It.IsAny <CallSettings>()), Times.Once());
        }
        public async Task ParallelMutationCommandsOnAmbientTransaction_OnlyCreateOneSpannerTransactionAsync()
        {
            Mock <SpannerClient> spannerClientMock = SpannerClientHelpers
                                                     .CreateMockClient(Logger.DefaultLogger, MockBehavior.Strict);

            spannerClientMock
            .SetupBatchCreateSessionsAsync()
            .SetupBeginTransactionAsync()
            .SetupCommitAsync();

            using (TransactionScope scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
            {
                SpannerConnection connection = BuildSpannerConnection(spannerClientMock);

                var tables = new string[] { "TAB1", "TAB2", "TAB3" };
                await Task.WhenAll(tables.Select(table =>
                {
                    using var cmd = connection.CreateInsertCommand(table);
                    return(cmd.ExecuteNonQueryAsync());
                }));

                scope.Complete();
            }

            spannerClientMock.Verify(client => client.CommitAsync(
                                         It.IsAny <CommitRequest>(), It.IsAny <CallSettings>()), Times.Once());
            spannerClientMock.Verify(client => client.CommitAsync(
                                         It.Is <CommitRequest>(request => request.Mutations.Count == 3),
                                         It.IsAny <CallSettings>()), Times.Once());
        }
        public void EphemeralTransactionIncludesPriorityOnDmlCommandAndCommit()
        {
            var priority = Priority.Medium;
            Mock <SpannerClient> spannerClientMock = SpannerClientHelpers
                                                     .CreateMockClient(Logger.DefaultLogger, MockBehavior.Strict);

            spannerClientMock
            .SetupBatchCreateSessionsAsync()
            .SetupBeginTransactionAsync()
            .SetupExecuteStreamingSqlForDml(ResultSetStats.RowCountOneofCase.RowCountExact)
            .SetupCommitAsync();
            SpannerConnection connection = BuildSpannerConnection(spannerClientMock);

            var command = connection.CreateDmlCommand("UPDATE FOO SET BAR=1 WHERE ID=1");

            command.Priority = priority;
            command.ExecuteNonQuery();

            spannerClientMock.Verify(client => client.ExecuteStreamingSql(
                                         It.Is <ExecuteSqlRequest>(request => request.RequestOptions.Priority == PriorityConverter.ToProto(priority)),
                                         It.IsAny <CallSettings>()), Times.Once());
            spannerClientMock.Verify(client => client.CommitAsync(
                                         It.Is <CommitRequest>(request => request.RequestOptions.Priority == PriorityConverter.ToProto(priority)),
                                         It.IsAny <CallSettings>()), Times.Once());
        }
        public void CommandIncludesPriority()
        {
            var priority = Priority.High;
            Mock <SpannerClient> spannerClientMock = SpannerClientHelpers
                                                     .CreateMockClient(Logger.DefaultLogger, MockBehavior.Strict);

            spannerClientMock
            .SetupBatchCreateSessionsAsync()
            .SetupBeginTransactionAsync()
            .SetupExecuteBatchDmlAsync()
            .SetupCommitAsync();
            SpannerConnection  connection  = SpannerCommandTests.BuildSpannerConnection(spannerClientMock);
            SpannerTransaction transaction = connection.BeginTransaction();

            var command = transaction.CreateBatchDmlCommand();

            command.Add("UPDATE FOO SET BAR=1 WHERE TRUE");
            command.Priority = priority;
            command.ExecuteNonQuery();
            transaction.Commit();

            spannerClientMock.Verify(client => client.ExecuteBatchDmlAsync(
                                         It.Is <ExecuteBatchDmlRequest>(request => request.RequestOptions.Priority == PriorityConverter.ToProto(priority)),
                                         It.IsAny <CallSettings>()), Times.Once());
        }
        public void TransactionTagCannotBeSetAfterCommandExecution()
        {
            var transactionTag = "transaction-tag-1";
            Mock <SpannerClient> spannerClientMock = SpannerClientHelpers
                                                     .CreateMockClient(Logger.DefaultLogger, MockBehavior.Strict);

            spannerClientMock
            .SetupBatchCreateSessionsAsync()
            .SetupBeginTransactionAsync()
            .SetupExecuteStreamingSql()
            .SetupCommitAsync();
            SpannerConnection  connection  = BuildSpannerConnection(spannerClientMock);
            SpannerTransaction transaction = connection.BeginTransaction();

            // Execute a command on the transaction without a transaction tag.
            var command1 = connection.CreateSelectCommand("SELECT * FROM FOO");

            command1.Transaction = transaction;
            using (var reader = command1.ExecuteReader())
            {
                Assert.True(reader.HasRows);
            }
            Assert.Throws <InvalidOperationException>(() => transaction.Tag = transactionTag);

            transaction.Commit();

            spannerClientMock.Verify(client => client.ExecuteStreamingSql(
                                         It.Is <ExecuteSqlRequest>(request => request.RequestOptions.RequestTag == "" && request.RequestOptions.TransactionTag == ""),
                                         It.IsAny <CallSettings>()), Times.Once());
            spannerClientMock.Verify(client => client.CommitAsync(
                                         It.Is <CommitRequest>(request => request.RequestOptions.RequestTag == "" && request.RequestOptions.TransactionTag == ""),
                                         It.IsAny <CallSettings>()), Times.Once());
        }
        public void CommitPriorityCanBeSetAfterCommandExecution()
        {
            var priority = Priority.Medium;
            Mock <SpannerClient> spannerClientMock = SpannerClientHelpers
                                                     .CreateMockClient(Logger.DefaultLogger, MockBehavior.Strict);

            spannerClientMock
            .SetupBatchCreateSessionsAsync()
            .SetupBeginTransactionAsync()
            .SetupExecuteStreamingSql()
            .SetupCommitAsync();
            SpannerConnection  connection  = BuildSpannerConnection(spannerClientMock);
            SpannerTransaction transaction = connection.BeginTransaction();

            // Execute a command on the transaction.
            var command = connection.CreateSelectCommand("SELECT * FROM FOO");

            command.Transaction = transaction;
            using (var reader = command.ExecuteReader())
            {
                Assert.True(reader.HasRows);
            }
            // Verify that we can set the commit priority after a command has been executed.
            transaction.CommitPriority = priority;
            transaction.Commit();

            spannerClientMock.Verify(client => client.CommitAsync(
                                         It.Is <CommitRequest>(request => request.RequestOptions.Priority == PriorityConverter.ToProto(priority)),
                                         It.IsAny <CallSettings>()), Times.Once());
        }
            public async Task BatchDmlAbortsTwice()
            {
                var spannerClientMock = SpannerClientHelpers
                                        .CreateMockClient(Logger.DefaultLogger, MockBehavior.Strict)
                                        .SetupBatchCreateSessionsAsync()
                                        .SetupBeginTransactionAsync()
                                        .SetupExecuteBatchDmlAsync_Fails(failures: 2, statusCode: StatusCode.Aborted)
                                        .SetupCommitAsync()
                                        .SetupRollbackAsync();

                SpannerConnection connection = BuildSpannerConnection(spannerClientMock);

                var scheduler = (FakeScheduler)connection.Builder.SessionPoolManager.SpannerSettings.Scheduler;
                var time0     = scheduler.Clock.GetCurrentDateTimeUtc();
                var callee    = new Callee(scheduler);

                await scheduler.RunAsync(async() =>
                {
                    var result = await connection.RunWithRetriableTransactionAsync(transaction => callee.DatabaseWorkAsync(connection, transaction));
                    Assert.Equal(3, result);
                });

                callee.AssertBackoffTimesInRange(time0);
                callee.AssertLastCallTime(scheduler.Clock.GetCurrentDateTimeUtc());
            }
        public void CommandHasConnectionQueryOptions()
        {
            const string         connOptimizerVersion           = "1";
            const string         connOptimizerStatisticsPackage = "stats_package_1";
            Mock <SpannerClient> spannerClientMock = SpannerClientHelpers
                                                     .CreateMockClient(Logger.DefaultLogger, MockBehavior.Strict);

            spannerClientMock
            .SetupBatchCreateSessionsAsync()
            .SetupExecuteStreamingSql();

            SpannerConnection connection = BuildSpannerConnection(spannerClientMock);

            connection.QueryOptions = QueryOptions.Empty
                                      .WithOptimizerVersion(connOptimizerVersion)
                                      .WithOptimizerStatisticsPackage(connOptimizerStatisticsPackage);

            var command = connection.CreateSelectCommand("SELECT * FROM FOO");

            using (var reader = command.ExecuteReader())
            {
                Assert.True(reader.HasRows);
            }

            spannerClientMock.Verify(client => client.ExecuteStreamingSql(
                                         It.Is <ExecuteSqlRequest>(request =>
                                                                   request.QueryOptions.OptimizerVersion == connOptimizerVersion &&
                                                                   request.QueryOptions.OptimizerStatisticsPackage == connOptimizerStatisticsPackage),
                                         It.IsAny <CallSettings>()), Times.Once());
        }
        public void TagsCanBeSetToNull()
        {
            Mock <SpannerClient> spannerClientMock = SpannerClientHelpers
                                                     .CreateMockClient(Logger.DefaultLogger, MockBehavior.Strict);

            spannerClientMock
            .SetupBatchCreateSessionsAsync()
            .SetupBeginTransactionAsync()
            .SetupExecuteStreamingSql()
            .SetupCommitAsync();
            SpannerConnection  connection  = BuildSpannerConnection(spannerClientMock);
            SpannerTransaction transaction = connection.BeginTransaction();

            transaction.Tag = null;

            var command = connection.CreateSelectCommand("SELECT * FROM FOO");

            command.Transaction = transaction;
            command.Tag         = null;
            using (var reader = command.ExecuteReader())
            {
                Assert.True(reader.HasRows);
            }
            transaction.Commit();

            spannerClientMock.Verify(client => client.ExecuteStreamingSql(
                                         It.Is <ExecuteSqlRequest>(request => request.RequestOptions.RequestTag == "" && request.RequestOptions.TransactionTag == ""),
                                         It.IsAny <CallSettings>()), Times.Once());
            spannerClientMock.Verify(client => client.CommitAsync(
                                         It.Is <CommitRequest>(request => request.RequestOptions.RequestTag == "" && request.RequestOptions.TransactionTag == ""),
                                         It.IsAny <CallSettings>()), Times.Once());
        }
            public async Task CommitFailsOtherThanAborted()
            {
                var spannerClientMock = SpannerClientHelpers
                                        .CreateMockClient(Logger.DefaultLogger, MockBehavior.Strict)
                                        .SetupBatchCreateSessionsAsync()
                                        .SetupBeginTransactionAsync()
                                        .SetupExecuteBatchDmlAsync()
                                        .SetupCommitAsync_Fails(failures: 1, StatusCode.Unknown)
                                        .SetupRollbackAsync();

                SpannerConnection connection = BuildSpannerConnection(spannerClientMock);

                var scheduler = (FakeScheduler)connection.Builder.SessionPoolManager.SpannerSettings.Scheduler;
                var time0     = scheduler.Clock.GetCurrentDateTimeUtc();
                var callee    = new Callee(scheduler);

                await scheduler.RunAsync(async() =>
                {
                    var exception = await Assert.ThrowsAsync <SpannerException>(
                        () => connection.RunWithRetriableTransactionAsync(
                            transaction => callee.DatabaseWorkAsync(connection, transaction)));
                    Assert.Contains("Bang!", exception.InnerException.Message);
                });

                callee.AssertBackoffTimesInRange(time0);
                callee.AssertLastCallTime(scheduler.Clock.GetCurrentDateTimeUtc());
            }
        public void RunWithRetryableTransactionWithTransactionTag()
        {
            var transactionTag = "retryable-tx-tag";
            Mock <SpannerClient> spannerClientMock = SpannerClientHelpers
                                                     .CreateMockClient(Logger.DefaultLogger, MockBehavior.Strict);

            spannerClientMock
            .SetupBatchCreateSessionsAsync()
            .SetupBeginTransactionAsync()
            .SetupExecuteStreamingSql()
            .SetupCommitAsync_Fails(1, StatusCode.Aborted, exceptionRetryDelay: TimeSpan.FromMilliseconds(0))
            .SetupRollbackAsync();
            SpannerConnection connection = BuildSpannerConnection(spannerClientMock);

            connection.Builder.SessionPoolManager.SpannerSettings.Scheduler = new NoOpScheduler();

            connection.RunWithRetriableTransaction(tx =>
            {
                tx.Tag              = transactionTag;
                var command         = connection.CreateSelectCommand("SELECT * FROM FOO");
                command.Transaction = tx;
                command.Tag         = null;
                using (var reader = command.ExecuteReader())
                {
                    Assert.True(reader.HasRows);
                }
            });
            spannerClientMock.Verify(client => client.ExecuteStreamingSql(
                                         It.Is <ExecuteSqlRequest>(request => request.RequestOptions.TransactionTag == transactionTag),
                                         It.IsAny <CallSettings>()), Times.Exactly(2));
            spannerClientMock.Verify(client => client.CommitAsync(
                                         It.Is <CommitRequest>(request => request.RequestOptions.TransactionTag == transactionTag),
                                         It.IsAny <CallSettings>()), Times.Exactly(2));
        }
        public void CommandIncludesRequestAndTransactionTag()
        {
            var requestTag1    = "request-tag-1";
            var requestTag2    = "request-tag-2";
            var transactionTag = "transaction-tag-1";
            Mock <SpannerClient> spannerClientMock = SpannerClientHelpers
                                                     .CreateMockClient(Logger.DefaultLogger, MockBehavior.Strict);

            spannerClientMock
            .SetupBatchCreateSessionsAsync()
            .SetupBeginTransactionAsync()
            .SetupExecuteStreamingSql()
            .SetupCommitAsync();
            SpannerConnection  connection  = BuildSpannerConnection(spannerClientMock);
            SpannerTransaction transaction = connection.BeginTransaction();

            transaction.Tag = transactionTag;

            var command1 = connection.CreateSelectCommand("SELECT * FROM FOO");

            command1.Transaction = transaction;
            command1.Tag         = requestTag1;
            using (var reader = command1.ExecuteReader())
            {
                Assert.True(reader.HasRows);
            }

            var command2 = connection.CreateSelectCommand("SELECT * FROM FOO");

            command2.Transaction = transaction;
            command2.Tag         = requestTag2;
            using (var reader = command2.ExecuteReader())
            {
                Assert.True(reader.HasRows);
            }

            // Execute a statement without a request tag on the same transaction.
            var command3 = connection.CreateSelectCommand("SELECT * FROM FOO");

            command3.Transaction = transaction;
            using (var reader = command3.ExecuteReader())
            {
                Assert.True(reader.HasRows);
            }
            transaction.Commit();

            spannerClientMock.Verify(client => client.ExecuteStreamingSql(
                                         It.Is <ExecuteSqlRequest>(request => request.RequestOptions.RequestTag == requestTag1 && request.RequestOptions.TransactionTag == transactionTag),
                                         It.IsAny <CallSettings>()), Times.Once());
            spannerClientMock.Verify(client => client.ExecuteStreamingSql(
                                         It.Is <ExecuteSqlRequest>(request => request.RequestOptions.RequestTag == requestTag2 && request.RequestOptions.TransactionTag == transactionTag),
                                         It.IsAny <CallSettings>()), Times.Once());
            spannerClientMock.Verify(client => client.ExecuteStreamingSql(
                                         It.Is <ExecuteSqlRequest>(request => request.RequestOptions.RequestTag == "" && request.RequestOptions.TransactionTag == transactionTag),
                                         It.IsAny <CallSettings>()), Times.Once());
            spannerClientMock.Verify(client => client.CommitAsync(
                                         It.Is <CommitRequest>(request => request.RequestOptions.RequestTag == "" && request.RequestOptions.TransactionTag == transactionTag),
                                         It.IsAny <CallSettings>()), Times.Once());
        }
        public void CommitPriorityDefaultsToUnspecified()
        {
            Mock <SpannerClient> spannerClientMock = SpannerClientHelpers
                                                     .CreateMockClient(Logger.DefaultLogger, MockBehavior.Strict);

            spannerClientMock
            .SetupBatchCreateSessionsAsync()
            .SetupBeginTransactionAsync();
            SpannerConnection  connection  = BuildSpannerConnection(spannerClientMock);
            SpannerTransaction transaction = connection.BeginTransaction();

            Assert.Equal(Priority.Unspecified, transaction.CommitPriority);
        }
        public void TransactionTagCannotBeSetForReadOnlyTransaction()
        {
            Mock <SpannerClient> spannerClientMock = SpannerClientHelpers
                                                     .CreateMockClient(Logger.DefaultLogger, MockBehavior.Strict);

            spannerClientMock
            .SetupBatchCreateSessionsAsync()
            .SetupBeginTransactionAsync();
            SpannerConnection  connection  = BuildSpannerConnection(spannerClientMock);
            SpannerTransaction transaction = connection.BeginReadOnlyTransaction();

            Assert.Throws <InvalidOperationException>(() => transaction.Tag = "transaction-tag-1");
        }
Example #17
0
        private Mock <SpannerClient> SetupExecuteStreamingSql(string optimizerVersion = "")
        {
            Mock <SpannerClient> spannerClientMock = SpannerClientHelpers
                                                     .CreateMockClient(Logger.DefaultLogger, MockBehavior.Strict);

            spannerClientMock
            .SetupBatchCreateSessionsAsync()
            .Setup(client => client.ExecuteStreamingSql(
                       It.Is <ExecuteSqlRequest>(request => request.QueryOptions.OptimizerVersion == optimizerVersion),
                       It.IsAny <CallSettings>()))
            .Returns <ExecuteSqlRequest, CallSettings>((request, _) => null);
            return(spannerClientMock);
        }
        public void PdmlRetriedOnEosError()
        {
            Mock<SpannerClient> spannerClientMock = SpannerClientHelpers
                .CreateMockClient(Logger.DefaultLogger, MockBehavior.Strict);
            spannerClientMock
                .SetupBatchCreateSessionsAsync()
                .SetupBeginTransactionAsync()
                .SetupExecuteStreamingSqlForDmlThrowingEosError();

            SpannerConnection connection = BuildSpannerConnection(spannerClientMock);

            var command = connection.CreateDmlCommand("UPDATE abc SET xyz = 1 WHERE Id > 1");
            long rowCount = command.ExecutePartitionedUpdate();
            Assert.True(rowCount > 0);
            spannerClientMock.Verify(client => client.ExecuteStreamingSql(
                It.IsAny<ExecuteSqlRequest>(),
                It.IsAny<CallSettings>()), Times.Exactly(3));
        }
        public void ExecuteReaderHasResourceHeader()
        {
            Mock<SpannerClient> spannerClientMock = SpannerClientHelpers
                .CreateMockClient(Logger.DefaultLogger, MockBehavior.Strict);
            spannerClientMock
                .SetupBatchCreateSessionsAsync()
                .SetupExecuteStreamingSql();

            SpannerConnection connection = BuildSpannerConnection(spannerClientMock);

            var command = connection.CreateSelectCommand("SELECT * FROM FOO");
            using (var reader = command.ExecuteReader())
            {
                Assert.True(reader.HasRows);
            }
            spannerClientMock.Verify(client => client.ExecuteStreamingSql(
                It.IsAny<ExecuteSqlRequest>(),
                It.Is<CallSettings>(settings => HasResourcePrefixHeader(settings))), Times.Once());
        }
        public void ClientCreatedWithEmulatorDetection()
        {
            Mock <SpannerClient> spannerClientMock = SpannerClientHelpers
                                                     .CreateMockClient(Logger.DefaultLogger, MockBehavior.Strict);

            spannerClientMock
            .SetupBatchCreateSessionsAsync()
            .SetupExecuteStreamingSql();

            var spannerClient      = spannerClientMock.Object;
            var sessionPoolOptions = new SessionPoolOptions
            {
                MaintenanceLoopDelay = TimeSpan.Zero
            };

            var sessionPoolManager = new SessionPoolManager(
                sessionPoolOptions, spannerClient.Settings.Logger,
                (_o, _s, _l) =>
            {
                Assert.True(_o.UsesEmulator);
                return(Task.FromResult(spannerClient));
            });

            SpannerConnectionStringBuilder builder = new SpannerConnectionStringBuilder
            {
                DataSource                  = DatabaseName.Format(SpannerClientHelpers.ProjectId, SpannerClientHelpers.Instance, SpannerClientHelpers.Database),
                SessionPoolManager          = sessionPoolManager,
                EmulatorDetection           = EmulatorDetection.EmulatorOrProduction,
                EnvironmentVariableProvider = key => key == "SPANNER_EMULATOR_HOST" ? "localhost" : null
            };
            var connection = new SpannerConnection(builder);

            var command = connection.CreateSelectCommand("SELECT * FROM FOO");

            using (var reader = command.ExecuteReader())
            {
                Assert.True(reader.HasRows);
            }
            spannerClientMock.Verify(client => client.ExecuteStreamingSql(
                                         It.IsAny <ExecuteSqlRequest>(),
                                         It.IsAny <CallSettings>()), Times.Once());
        }
        public void MutationCommandIncludesPriority()
        {
            Mock <SpannerClient> spannerClientMock = SpannerClientHelpers
                                                     .CreateMockClient(Logger.DefaultLogger, MockBehavior.Strict);

            spannerClientMock
            .SetupBatchCreateSessionsAsync()
            .SetupBeginTransactionAsync()
            .SetupCommitAsync();
            SpannerConnection connection = BuildSpannerConnection(spannerClientMock);

            var command = connection.CreateInsertCommand("FOO");

            command.Priority = Priority.High;
            command.ExecuteNonQuery();

            spannerClientMock.Verify(client => client.CommitAsync(
                                         It.Is <CommitRequest>(request => request.RequestOptions.Priority == RequestOptions.Types.Priority.High),
                                         It.IsAny <CallSettings>()), Times.Once());
        }
        public void PdmlCommandIncludesPriority()
        {
            Mock <SpannerClient> spannerClientMock = SpannerClientHelpers
                                                     .CreateMockClient(Logger.DefaultLogger, MockBehavior.Strict);

            spannerClientMock
            .SetupBatchCreateSessionsAsync()
            .SetupBeginTransactionAsync()
            .SetupExecuteStreamingSqlForDml(ResultSetStats.RowCountOneofCase.RowCountLowerBound);
            SpannerConnection connection = BuildSpannerConnection(spannerClientMock);

            var command = connection.CreateDmlCommand("DELETE FROM Users WHERE Active=False");

            command.Priority = Priority.Low;
            command.ExecutePartitionedUpdate();

            spannerClientMock.Verify(client => client.ExecuteStreamingSql(
                                         It.Is <ExecuteSqlRequest>(request => request.RequestOptions.Priority == RequestOptions.Types.Priority.Low),
                                         It.IsAny <CallSettings>()), Times.Once());
        }
        public void CommandIncludesRequestTag()
        {
            var tag = "tag-1";
            Mock <SpannerClient> spannerClientMock = SpannerClientHelpers
                                                     .CreateMockClient(Logger.DefaultLogger, MockBehavior.Strict);

            spannerClientMock
            .SetupBatchCreateSessionsAsync()
            .SetupExecuteStreamingSql();
            SpannerConnection connection = BuildSpannerConnection(spannerClientMock);

            var command = connection.CreateSelectCommand("SELECT * FROM FOO");

            command.Tag = tag;
            using (var reader = command.ExecuteReader())
            {
                Assert.True(reader.HasRows);
            }
            spannerClientMock.Verify(client => client.ExecuteStreamingSql(
                                         It.Is <ExecuteSqlRequest>(request => request.RequestOptions.RequestTag == tag && request.RequestOptions.TransactionTag == ""),
                                         It.IsAny <CallSettings>()));
        }
            public async Task WorkFails()
            {
                var spannerClientMock = SpannerClientHelpers
                                        .CreateMockClient(Logger.DefaultLogger, MockBehavior.Strict)
                                        .SetupBatchCreateSessionsAsync()
                                        .SetupBeginTransactionAsync()
                                        .SetupRollbackAsync();

                SpannerConnection connection = BuildSpannerConnection(spannerClientMock);

                var scheduler = (FakeScheduler)connection.Builder.SessionPoolManager.SpannerSettings.Scheduler;
                var time0     = scheduler.Clock.GetCurrentDateTimeUtc();
                var callee    = new Callee(scheduler);

                await scheduler.RunAsync(async() =>
                {
                    var exception = await Assert.ThrowsAsync <InvalidOperationException>(() => connection.RunWithRetriableTransactionAsync(callee.Fails));
                    Assert.Contains("Bang!", exception.Message);
                });

                callee.AssertBackoffTimesInRange(time0);
                callee.AssertLastCallTime(scheduler.Clock.GetCurrentDateTimeUtc());
            }
            public async Task CommitAbortsAlways_RespectsOverallDeadline()
            {
                var spannerClientMock = SpannerClientHelpers
                                        .CreateMockClient(Logger.DefaultLogger, MockBehavior.Strict)
                                        .SetupBatchCreateSessionsAsync()
                                        .SetupBeginTransactionAsync()
                                        .SetupExecuteBatchDmlAsync()
                                        .SetupCommitAsync_FailsAlways(statusCode: StatusCode.Aborted)
                                        .SetupRollbackAsync();

                SpannerConnection connection = BuildSpannerConnection(spannerClientMock);

                var scheduler = (FakeScheduler)connection.Builder.SessionPoolManager.SpannerSettings.Scheduler;

                // This test needs a little bit more of real time, else it's flaky.
                scheduler.RealTimeTimeout = TimeSpan.FromSeconds(60);
                var time0  = scheduler.Clock.GetCurrentDateTimeUtc();
                var callee = new Callee(scheduler);

                await scheduler.RunAsync(async() =>
                {
                    var exception = await Assert.ThrowsAsync <SpannerException>(() => connection.RunWithRetriableTransactionAsync(transaction => callee.DatabaseWorkAsync(connection, transaction)));
                    Assert.True(exception.IsRetryable && !exception.SessionExpired);
                    Assert.Contains("Bang!", exception.InnerException.Message);
                });

                // The minimum calls that can be made (assuming maximum jitter always) in that time is 60 * 60 / 32 * 2 which is 56.25,
                // plus 1 because the first one has no delay.
                // The maximum number of calls that can be made in 1 hour:
                // - Given that 2^7 * 250 = 32000, the first 8 calls take, at a minimum 31_750ms, approx 32s.
                // - The rest will happen at most (60 * 60 - 32) / 32 which is 111.5
                callee.AssertCalledInRange(57, 120);
                // The overall deadline is of 1 hour. The maximum backoff delay is of 32s.
                // Because of jitter retries can stop at any time after 60mins - 64s, let's give it 2 minutes of range.
                Assert.InRange(scheduler.Clock.GetCurrentDateTimeUtc(), time0.AddMinutes(58), time0.AddMinutes(60));
            }
        public void CommandHasQueryOptionsFromEnvironment()
        {
            Mock <SpannerClient> spannerClientMock = SpannerClientHelpers
                                                     .CreateMockClient(Logger.DefaultLogger, MockBehavior.Strict);

            spannerClientMock
            .SetupBatchCreateSessionsAsync()
            .SetupExecuteStreamingSql();

            const string envOptimizerVersion           = "2";
            const string envOptimizerStatisticsPackage = "stats_package_2";

            RunActionWithEnvQueryOptions(() =>
            {
                // Optimizer version set through environment variable has higher
                // precedence than version set through connection.
                const string connOptimizerVersion           = "1";
                const string connOptimizerStatisticsPackage = "stats_package_1";
                SpannerConnection connection = BuildSpannerConnection(spannerClientMock);
                connection.QueryOptions      = QueryOptions.Empty
                                               .WithOptimizerVersion(connOptimizerVersion)
                                               .WithOptimizerStatisticsPackage(connOptimizerStatisticsPackage);

                var command = connection.CreateSelectCommand("SELECT * FROM FOO");
                using (var reader = command.ExecuteReader())
                {
                    Assert.True(reader.HasRows);
                }
            }, envOptimizerVersion, envOptimizerStatisticsPackage);

            spannerClientMock.Verify(client => client.ExecuteStreamingSql(
                                         It.Is <ExecuteSqlRequest>(request =>
                                                                   request.QueryOptions.OptimizerVersion == envOptimizerVersion &&
                                                                   request.QueryOptions.OptimizerStatisticsPackage == envOptimizerStatisticsPackage),
                                         It.IsAny <CallSettings>()), Times.Once());
        }