async Task ReceiverShouldUseTheLatestPrefetchCount()
        {
            await ServiceBusScope.UsingQueueAsync(partitioned : false, sessionEnabled : false, async queueName =>
            {
                var sender = new MessageSender(TestUtility.NamespaceConnectionString, queueName);

                var receiver1 = new MessageReceiver(TestUtility.NamespaceConnectionString, queueName, receiveMode: ReceiveMode.ReceiveAndDelete);
                var receiver2 = new MessageReceiver(TestUtility.NamespaceConnectionString, queueName, receiveMode: ReceiveMode.ReceiveAndDelete, prefetchCount: 1);

                Assert.Equal(0, receiver1.PrefetchCount);
                Assert.Equal(1, receiver2.PrefetchCount);

                try
                {
                    for (var i = 0; i < 9; i++)
                    {
                        var message = new Message(Encoding.UTF8.GetBytes("test" + i))
                        {
                            Label = "prefetch" + i
                        };
                        await sender.SendAsync(message).ConfigureAwait(false);
                    }

                    // Default prefetch count should be 0 for receiver 1.
                    Assert.Equal("prefetch0", (await receiver1.ReceiveAsync().ConfigureAwait(false)).Label);

                    // The first ReceiveAsync() would initialize the link and block prefetch2 for receiver2
                    Assert.Equal("prefetch1", (await receiver2.ReceiveAsync().ConfigureAwait(false)).Label);
                    await Task.Delay(TwoSeconds);

                    // Updating prefetch count on receiver1.
                    receiver1.PrefetchCount = 2;
                    await Task.Delay(TwoSeconds);

                    // The next operation should fetch prefetch3 and prefetch4.
                    Assert.Equal("prefetch3", (await receiver1.ReceiveAsync().ConfigureAwait(false)).Label);
                    await Task.Delay(TwoSeconds);

                    Assert.Equal("prefetch2", (await receiver2.ReceiveAsync().ConfigureAwait(false)).Label);
                    await Task.Delay(TwoSeconds);

                    // The next operation should block prefetch6 for receiver2.
                    Assert.Equal("prefetch5", (await receiver2.ReceiveAsync().ConfigureAwait(false)).Label);
                    await Task.Delay(TwoSeconds);

                    // Updates in prefetch count of receiver1 should not affect receiver2.
                    // Receiver2 should continue with 1 prefetch.
                    Assert.Equal("prefetch4", (await receiver1.ReceiveAsync().ConfigureAwait(false)).Label);
                    Assert.Equal("prefetch7", (await receiver1.ReceiveAsync().ConfigureAwait(false)).Label);
                    Assert.Equal("prefetch8", (await receiver1.ReceiveAsync().ConfigureAwait(false)).Label);
                }
                catch (Exception)
                {
                    // Cleanup
                    Message message;
                    do
                    {
                        message = await receiver1.ReceiveAsync(TimeSpan.FromSeconds(3)).ConfigureAwait(false);
                    } while (message != null);
                }
                finally
                {
                    await sender.CloseAsync().ConfigureAwait(false);
                    await receiver1.CloseAsync().ConfigureAwait(false);
                    await receiver2.CloseAsync().ConfigureAwait(false);
                }
            });
        }
        private async Task OnMessageTestAsync(bool partitioned, bool sessionEnabled, int maxConcurrentCalls, ReceiveMode mode, bool autoComplete)
        {
            const int messageCount = 10;

            await ServiceBusScope.UsingTopicAsync(partitioned, sessionEnabled, async (topicName, subscriptionName) =>
            {
                var topicClient        = new TopicClient(TestUtility.NamespaceConnectionString, topicName);
                var subscriptionClient = new SubscriptionClient(
                    TestUtility.NamespaceConnectionString,
                    topicName,
                    subscriptionName,
                    mode);

                try
                {
                    await this.OnMessageAsyncTestCase(
                        topicClient.InnerSender,
                        subscriptionClient.InnerSubscriptionClient.InnerReceiver,
                        maxConcurrentCalls,
                        autoComplete,
                        messageCount);
                }
                finally
                {
                    await subscriptionClient.CloseAsync();
                    await topicClient.CloseAsync();
                }
            });

            await ServiceBusScope.UsingTopicAsync(partitioned, sessionEnabled, async (topicName, subscriptionName) =>
            {
                var topicClient        = new TopicClient(TestUtility.NamespaceConnectionString, topicName);
                var subscriptionClient = new SubscriptionClient(
                    TestUtility.NamespaceConnectionString,
                    topicName,
                    subscriptionName,
                    mode);

                try
                {
                    await this.OnMessageAsyncUnregisterHandlerLongTimeoutTestCase(
                        topicClient.InnerSender,
                        subscriptionClient.InnerSubscriptionClient.InnerReceiver,
                        maxConcurrentCalls,
                        autoComplete,
                        messageCount);
                }
                finally
                {
                    await subscriptionClient.CloseAsync();
                    await topicClient.CloseAsync();
                }
            });

            await ServiceBusScope.UsingTopicAsync(partitioned, sessionEnabled, async (topicName, subscriptionName) =>
            {
                var topicClient        = new TopicClient(TestUtility.NamespaceConnectionString, topicName);
                var subscriptionClient = new SubscriptionClient(
                    TestUtility.NamespaceConnectionString,
                    topicName,
                    subscriptionName,
                    mode);

                try
                {
                    await this.OnMessageAsyncUnregisterHandlerShortTimeoutTestCase(
                        topicClient.InnerSender,
                        subscriptionClient.InnerSubscriptionClient.InnerReceiver,
                        maxConcurrentCalls,
                        autoComplete,
                        messageCount);
                }
                finally
                {
                    await subscriptionClient.CloseAsync();
                    await topicClient.CloseAsync();
                }
            });
        }
        private async Task OnSessionTestAsync(bool partitioned, bool sessionEnabled, int maxConcurrentCalls, ReceiveMode mode, bool autoComplete)
        {
            await ServiceBusScope.UsingTopicAsync(partitioned, sessionEnabled, async (topicName, subscriptionName) =>
            {
                TestUtility.Log($"Topic: {topicName}, MaxConcurrentCalls: {maxConcurrentCalls}, Receive Mode: {mode.ToString()}, AutoComplete: {autoComplete}");
                var topicClient        = new TopicClient(TestUtility.NamespaceConnectionString, topicName);
                var subscriptionClient = new SubscriptionClient(
                    TestUtility.NamespaceConnectionString,
                    topicClient.TopicName,
                    subscriptionName,
                    ReceiveMode.PeekLock);

                try
                {
                    var sessionHandlerOptions =
                        new SessionHandlerOptions(ExceptionReceivedHandler)
                    {
                        MaxConcurrentSessions = maxConcurrentCalls,
                        MessageWaitTimeout    = TimeSpan.FromSeconds(5),
                        AutoComplete          = true
                    };

                    var testSessionHandler = new TestSessionHandler(
                        subscriptionClient.ReceiveMode,
                        sessionHandlerOptions,
                        topicClient.InnerSender,
                        subscriptionClient.SessionPumpHost);

                    // Send messages to Session
                    await testSessionHandler.SendSessionMessages();

                    // Register handler
                    testSessionHandler.RegisterSessionHandler(sessionHandlerOptions);

                    // Verify messages were received.
                    await testSessionHandler.VerifyRun();

                    testSessionHandler.ClearData();
                }
                finally
                {
                    await subscriptionClient.CloseAsync();
                    await topicClient.CloseAsync();
                }
            });

            // test UnregisterSessionHandler can wait for message handling upto the timeout user defined.
            await ServiceBusScope.UsingTopicAsync(partitioned, sessionEnabled, async (topicName, subscriptionName) =>
            {
                TestUtility.Log($"Topic: {topicName}, MaxConcurrentCalls: {maxConcurrentCalls}, Receive Mode: {mode.ToString()}, AutoComplete: {autoComplete}");
                var topicClient        = new TopicClient(TestUtility.NamespaceConnectionString, topicName);
                var subscriptionClient = new SubscriptionClient(
                    TestUtility.NamespaceConnectionString,
                    topicClient.TopicName,
                    subscriptionName,
                    ReceiveMode.PeekLock);

                try
                {
                    var sessionHandlerOptions =
                        new SessionHandlerOptions(ExceptionReceivedHandler)
                    {
                        MaxConcurrentSessions = maxConcurrentCalls,
                        MessageWaitTimeout    = TimeSpan.FromSeconds(5),
                        AutoComplete          = true
                    };

                    var testSessionHandler = new TestSessionHandler(
                        subscriptionClient.ReceiveMode,
                        sessionHandlerOptions,
                        topicClient.InnerSender,
                        subscriptionClient.SessionPumpHost);

                    // Send messages to Session
                    await testSessionHandler.SendSessionMessages();

                    // Register handler
                    var count = 0;
                    testSessionHandler.RegisterSessionHandler(
                        async(session, message, token) =>
                    {
                        await Task.Delay(TimeSpan.FromSeconds(8));
                        TestUtility.Log($"Received Session: {session.SessionId} message: SequenceNumber: {message.SystemProperties.SequenceNumber}");

                        if (subscriptionClient.ReceiveMode == ReceiveMode.PeekLock && !sessionHandlerOptions.AutoComplete)
                        {
                            await session.CompleteAsync(message.SystemProperties.LockToken);
                        }
                        Interlocked.Increment(ref count);
                    },
                        sessionHandlerOptions);

                    await Task.Delay(TimeSpan.FromSeconds(2));
                    // UnregisterSessionHandler should wait up to the provided timeout to finish the message handling tasks
                    await testSessionHandler.UnregisterSessionHandler(TimeSpan.FromSeconds(10));
                    Assert.True(count == maxConcurrentCalls);

                    testSessionHandler.ClearData();
                }
                finally
                {
                    await subscriptionClient.CloseAsync();
                    await topicClient.CloseAsync();
                }
            });

            // test UnregisterSessionHandler can close down in time when message handling takes longer than wait timeout user defined.
            await ServiceBusScope.UsingTopicAsync(partitioned, sessionEnabled, async (topicName, subscriptionName) =>
            {
                TestUtility.Log($"Topic: {topicName}, MaxConcurrentCalls: {maxConcurrentCalls}, Receive Mode: {mode.ToString()}, AutoComplete: {autoComplete}");
                var topicClient        = new TopicClient(TestUtility.NamespaceConnectionString, topicName);
                var subscriptionClient = new SubscriptionClient(
                    TestUtility.NamespaceConnectionString,
                    topicClient.TopicName,
                    subscriptionName,
                    ReceiveMode.PeekLock);

                try
                {
                    var sessionHandlerOptions =
                        new SessionHandlerOptions(ExceptionReceivedHandler)
                    {
                        MaxConcurrentSessions = maxConcurrentCalls,
                        MessageWaitTimeout    = TimeSpan.FromSeconds(5),
                        AutoComplete          = true
                    };

                    var testSessionHandler = new TestSessionHandler(
                        subscriptionClient.ReceiveMode,
                        sessionHandlerOptions,
                        topicClient.InnerSender,
                        subscriptionClient.SessionPumpHost);

                    // Send messages to Session
                    await testSessionHandler.SendSessionMessages();

                    // Register handler
                    var count = 0;
                    testSessionHandler.RegisterSessionHandler(
                        async(session, message, token) =>
                    {
                        await Task.Delay(TimeSpan.FromSeconds(8));
                        TestUtility.Log($"Received Session: {session.SessionId} message: SequenceNumber: {message.SystemProperties.SequenceNumber}");

                        if (subscriptionClient.ReceiveMode == ReceiveMode.PeekLock && !sessionHandlerOptions.AutoComplete)
                        {
                            await session.CompleteAsync(message.SystemProperties.LockToken);
                        }
                        Interlocked.Increment(ref count);
                    },
                        sessionHandlerOptions);

                    await Task.Delay(TimeSpan.FromSeconds(2));
                    // UnregisterSessionHandler should wait up to the provided timeout to finish the message handling tasks
                    await testSessionHandler.UnregisterSessionHandler(TimeSpan.FromSeconds(2));
                    Assert.True(count == 0);

                    testSessionHandler.ClearData();
                }
                finally
                {
                    await subscriptionClient.CloseAsync();
                    await topicClient.CloseAsync();
                }
            });
        }