public async Task TestFlowAutoReadOn()
        {
            var latch = new CountdownEvent(3);

            ChannelHandlerAdapter handler = new TestHandler(onRead: (ctx, msg) => latch.Signal());

            var      flow   = new FlowControlHandler();
            IChannel server = await this.NewServer(true, flow, handler);

            IChannel client = await this.NewClient(server.LocalAddress);

            try
            {
                // Write the message
                await client.WriteAndFlushAsync(NewOneMessage());

                // We should receive 3 messages
                Assert.True(latch.Wait(TimeSpan.FromSeconds(1)));
                Assert.True(flow.IsQueueEmpty);
            }
            finally
            {
                Task.WhenAll(client.CloseAsync(), server.CloseAsync()).Wait(TimeSpan.FromSeconds(5));
            }
        }
        public async Task TestReentranceNotCausesNPE()
        {
            IChannel  channel  = null;
            var       mre      = new ManualResetEventSlim(false);
            var       latch    = new CountdownEvent(3);
            Exception causeRef = null;

            ChannelHandlerAdapter handler = new TestHandler(
                onActive: ctx =>
            {
                ctx.FireChannelActive();
                //peerRef.exchange(ctx.Channel, 1L, SECONDS);
                Interlocked.Exchange(ref channel, ctx.Channel);
                mre.Set();
            },
                onRead: (ctx, msg) =>
            {
                Signal(latch);
                ctx.Read();
            },
                onExceptionCaught: (ctx, exc) => Interlocked.Exchange(ref causeRef, exc)
                );

            var      flow   = new FlowControlHandler();
            IChannel server = await NewServer(false, flow, handler);

            IChannel client = await NewClient(server.LocalAddress);

            try
            {
                // The client connection on the server side
                mre.Wait(TimeSpan.FromSeconds(1));
                IChannel peer = Interlocked.Exchange(ref channel, null);

                // Write the message
                await client.WriteAndFlushAsync(NewOneMessage());

                // channelRead(1)
                peer.Read();
                Assert.True(latch.Wait(TimeSpan.FromSeconds(1)));
                Assert.True(flow.IsQueueEmpty);

                var exc = Volatile.Read(ref causeRef);
                Assert.Null(exc);
            }
            finally
            {
                Task.WhenAll(client.CloseAsync(), server.CloseAsync()).Wait(TimeSpan.FromSeconds(5));
            }

            void Signal(CountdownEvent evt)
            {
                if (!evt.IsSet)
                {
                    evt.Signal();
                }
            }
        }
        public async Task TestFlowAutoReadOff()
        {
            IChannel channel = null;
            var      mre     = new ManualResetEventSlim(false);

            var msgRcvLatch1 = new CountdownEvent(1);
            var msgRcvLatch2 = new CountdownEvent(2);
            var msgRcvLatch3 = new CountdownEvent(3);

            ChannelHandlerAdapter handler = new TestHandler(
                onActive: ctx =>
            {
                ctx.FireChannelActive();
                //peerRef.exchange(ctx.Channel, 1L, SECONDS);
                Interlocked.Exchange(ref channel, ctx.Channel);
                mre.Set();
            },
                onRead: (ctx, msg) =>
            {
                Signal(msgRcvLatch1);
                Signal(msgRcvLatch2);
                Signal(msgRcvLatch3);
            }
                );

            var      flow   = new FlowControlHandler();
            IChannel server = await this.NewServer(false, flow, handler);

            IChannel client = await this.NewClient(server.LocalAddress);

            try
            {
                // The client connection on the server side
                mre.Wait(TimeSpan.FromSeconds(1));
                IChannel peer = Interlocked.Exchange(ref channel, null);

                // Write the message
                await client.WriteAndFlushAsync(NewOneMessage());

                // channelRead(1)
                peer.Read();
                Assert.True(msgRcvLatch1.Wait(TimeSpan.FromSeconds(10)));

                // channelRead(2)
                peer.Read();
                Assert.True(msgRcvLatch2.Wait(TimeSpan.FromSeconds(10)));

                // channelRead(3)
                peer.Read();
                Assert.True(msgRcvLatch3.Wait(TimeSpan.FromSeconds(10)));
                Assert.True(flow.IsQueueEmpty);
            }
            finally
            {
                Task.WhenAll(client.CloseAsync(), server.CloseAsync()).Wait(TimeSpan.FromSeconds(5));
            }

            void Signal(CountdownEvent evt)
            {
                if (!evt.IsSet)
                {
                    evt.Signal();
                }
            }
        }
        public async Task TestFlowToggleAutoRead()
        {
            IChannel channel = null;
            var      mre     = new ManualResetEventSlim(false);

            var msgRcvLatch1      = new CountdownEvent(1);
            var msgRcvLatch2      = new CountdownEvent(1);
            var msgRcvLatch3      = new CountdownEvent(1);
            var setAutoReadLatch1 = new CountdownEvent(1);
            var setAutoReadLatch2 = new CountdownEvent(1);

            int msgRcvCount               = 0;
            int expectedMsgCount          = 0;
            ChannelHandlerAdapter handler = new TestHandler(
                onActive: ctx =>
            {
                Interlocked.Exchange(ref channel, ctx.Channel);
                mre.Set();
                ctx.FireChannelActive();
            },
                onRead: (ctx, msg) =>
            {
                ReferenceCountUtil.Release(msg);

                // Disable auto reading after each message
                ctx.Channel.Configuration.AutoRead = false;

                if (msgRcvCount++ != expectedMsgCount)
                {
                    return;
                }
                switch (msgRcvCount)
                {
                case 1:
                    msgRcvLatch1.Signal();
                    if (setAutoReadLatch1.Wait(TimeSpan.FromSeconds(1)))
                    {
                        ++expectedMsgCount;
                    }
                    break;

                case 2:
                    msgRcvLatch2.Signal();
                    if (setAutoReadLatch2.Wait(TimeSpan.FromSeconds(1)))
                    {
                        ++expectedMsgCount;
                    }
                    break;

                default:
                    msgRcvLatch3.Signal();
                    break;
                }
            }
                );

            var      flow   = new FlowControlHandler();
            IChannel server = await this.NewServer(true, flow, handler);

            IChannel client = await this.NewClient(server.LocalAddress);

            try
            {
                // The client connection on the server side
                mre.Wait(TimeSpan.FromSeconds(1));
                IChannel peer = Interlocked.Exchange(ref channel, null);

                await client.WriteAndFlushAsync(NewOneMessage());

                // channelRead(1)
                Assert.True(msgRcvLatch1.Wait(TimeSpan.FromSeconds(1)));

                // channelRead(2)
                peer.Configuration.AutoRead = true;
                setAutoReadLatch1.Signal();
                Assert.True(msgRcvLatch1.Wait(TimeSpan.FromSeconds(1)));

                // channelRead(3)
                peer.Configuration.AutoRead = true;
                setAutoReadLatch2.Signal();
                Assert.True(msgRcvLatch3.Wait(TimeSpan.FromSeconds(1)));
                Assert.True(flow.IsQueueEmpty);
            }
            finally
            {
                Task.WhenAll(client.CloseAsync(), server.CloseAsync()).Wait(TimeSpan.FromSeconds(5));
            }
        }