public async Task BeginTransactionAsync_ThrowsInvalidOperationException_WhileTransactionActive()
        {
            // Arrange
            var provider = new SqlServerServiceBroker(connection);
            var transaction = default(IServiceBrokerTransaction);

            // Act
            Func<Task> call1 = async () =>
            {
                try
                {
                    provider.UseTransaction(connection.BeginTransaction());
                    transaction = await provider.BeginTransactionAsync();
                }
                finally
                {
                    provider.UseTransaction(null);
                }
            };

            Func<Task> call2 = async () =>
            {
                try
                {
                    transaction = await provider.BeginTransactionAsync();
                    transaction = await provider.BeginTransactionAsync();
                }
                finally
                {
                    provider.UseTransaction(null);
                }
            };

            // Assert
            await Assert.ThrowsAsync<InvalidOperationException>(call1);
            Assert.Null(transaction);
            await Assert.ThrowsAsync<InvalidOperationException>(call2);
            Assert.NotNull(transaction);
        }
        public async Task SendAsync_UsesTransaction()
        {
            // Arrange
            await InitializeDatabaseAsync();
            var provider = new SqlServerServiceBroker(connection);
            var handle = await BeginDialogAsync();

            // Act
            using (var transaction = await provider.BeginTransactionAsync())
            {
                await provider.SendAsync(new SendArguments(handle));
                transaction.Rollback();
            }

            var received = await connection.QueryAsync("SELECT * FROM [TargetQueue] WITH (NOLOCK)");

            // Assert
            Assert.Empty(received);
        }
        public async Task ReceiveAsync_UsesTransaction()
        {
            // Arrange
            await InitializeDatabaseAsync();
            var provider = new SqlServerServiceBroker(connection);
            var handle = await BeginDialogAsync();
            await connection.ExecuteAsync("SEND ON CONVERSATION @handle;", new { handle });

            // Act
            var transaction = await provider.BeginTransactionAsync();
            var beforeRollback = await provider.ReceiveAsync(new ReceiveArguments("TargetQueue"));
            transaction.Rollback();
            var afterRollback = await provider.ReceiveAsync(new ReceiveArguments("TargetQueue"));

            // Assert
            Assert.NotEmpty(beforeRollback);
            Assert.NotEmpty(afterRollback);
        }
        public async Task MoveConversationAsync_UsesTransaction()
        {
            // Arrange
            await InitializeDatabaseAsync();
            var provider = new SqlServerServiceBroker(connection);
            var handle1 = await BeginDialogAsync();
            var handle2 = await BeginDialogAsync();
            var sql = @"SELECT [conversation_group_id] FROM sys.conversation_endpoints WHERE conversation_handle = @handle";
            var group1 = await connection.ExecuteScalarAsync<Guid>(sql, new { handle = handle1 });
            var group2 = await connection.ExecuteScalarAsync<Guid>(sql, new { handle = handle2 });

            // Act
            using (var transaction = await provider.BeginTransactionAsync())
            {
                await provider.MoveConversationAsync(new MoveConversationArguments(handle1, group2));
                transaction.Rollback();
            }

            var afterRollback = await connection.ExecuteScalarAsync<Guid>(sql, new { handle = handle1 });

            // Assert
            Assert.Equal(group1, afterRollback);
        }
        public async Task GetTransmissionStatusAsync_UsesTransaction()
        {
            // Arrange
            await InitializeDatabaseAsync();
            var provider = new SqlServerServiceBroker(connection);
            var handle = await BeginDialogAsync(encryption: true);

            // Act
            using (var transaction = await provider.BeginTransactionAsync())
            {
                await connection.ExecuteAsync("SEND ON CONVERSATION @handle;", new { handle }, transaction.UnderlyingTransaction);
                transaction.Rollback();
            }

            var status = await provider.GetTransmissionStatusAsync(new GetTransmissionStatusArguments(handle));

            // Assert
            Assert.Equal(string.Empty, status);
        }
        public async Task GetConversationGroupAsync_UsesTransaction()
        {
            // Arrange
            await InitializeDatabaseAsync();
            var provider1 = new SqlServerServiceBroker(connection);
            var provider2 = new SqlServerServiceBroker(new SqlConnection(connection.ConnectionString));
            var handle = await BeginDialogAsync();
            IEnumerable<ReceivedMessage> beforeRollback;
            IEnumerable<ReceivedMessage> afterRollback;
            await connection.ExecuteAsync("SEND ON CONVERSATION @handle;", new { handle });

            // Act
            using (var transaction = await provider1.BeginTransactionAsync())
            {
                var arguments = new GetConversationGroupArguments("TargetQueue");
                var groupId = await provider1.GetConversationGroupAsync(arguments);
                var receiveArgs = new ReceiveArguments("TargetQueue")
                {
                    Predicate = groupId.Value,
                    WaitFor = TimeSpan.FromSeconds(1),
                };

                beforeRollback = await provider2.ReceiveAsync(receiveArgs);
                transaction.Rollback();
                afterRollback = await provider2.ReceiveAsync(receiveArgs);
            }

            // Assert
            Assert.Empty(beforeRollback);
            Assert.NotEmpty(afterRollback);
        }
        public async Task EndConversationAsync_UsesTransaction()
        {
            // Arrange
            await InitializeDatabaseAsync();
            var provider = new SqlServerServiceBroker(connection);
            var handle = await BeginDialogAsync();

            // Act
            using (var transaction = await provider.BeginTransactionAsync())
            {
                await provider.EndConversationAsync(new EndConversationArguments(handle));
                transaction.Rollback();
            }

            var sql = @"SELECT [state] FROM sys.conversation_endpoints WHERE conversation_handle = @handle";
            var results = await connection.QueryAsync(sql, new { handle });

            // Assert
            Assert.NotEmpty(results);
        }
        public async Task BeginDialogAsync_UsesTransaction()
        {
            // Arrange
            await InitializeDatabaseAsync();
            var provider = new SqlServerServiceBroker(connection);
            var arguments = new BeginDialogArguments("InitiatorService", "TargetService");
            var handle = default(ConversationHandle);

            // Act
            using (var transaction = await provider.BeginTransactionAsync())
            {
                handle = await provider.BeginDialogAsync(arguments);
                transaction.Rollback();
            }

            var sql = @"SELECT * FROM sys.conversation_endpoints WHERE conversation_handle = @handle";
            var results = await connection.QueryAsync(sql, new { handle = handle.Value });

            // Assert
            Assert.Empty(results);
        }
        public async Task BeginConversationTimerAsync_UsesTransaction()
        {
            // Arrange
            await InitializeDatabaseAsync();
            var handle = await BeginDialogAsync();
            var provider = new SqlServerServiceBroker(connection);
            var arguments = new BeginConversationTimerArguments(handle, 600);

            // Act
            using (var transaction = await provider.BeginTransactionAsync())
            {
                await provider.BeginConversationTimerAsync(arguments);
                transaction.Rollback();
            }

            var sql = @"SELECT * FROM sys.conversation_endpoints WHERE conversation_handle = @handle";
            var results = await connection.QueryAsync(sql, new { handle });
            var scheduledTime = (DateTime)results.Single().dialog_timer;

            // Assert
            Assert.Equal(1900, scheduledTime.Year);
        }