Exemplo n.º 1
0
        public async Task EngineCanStartAndStop()
        {
            var engine = new KestrelEngine(LibraryManager);

            engine.Start(1);
            engine.Dispose();
        }
Exemplo n.º 2
0
        public IDisposable Start(IServerInformation serverInformation, Func <IFeatureCollection, Task> application)
        {
            var disposables = new List <IDisposable>();
            var information = (ServerInformation)serverInformation;
            var engine      = new KestrelEngine(_libraryManager, _appShutdownService);

            engine.Start(1);
            foreach (var address in information.Addresses)
            {
                disposables.Add(engine.CreateServer(
                                    address.Scheme,
                                    address.Host,
                                    address.Port,
                                    async frame =>
                {
                    var request = new ServerRequest(frame);
                    await application.Invoke(request.Features);
                }));
            }
            disposables.Add(engine);
            return(new Disposable(() =>
            {
                foreach (var disposable in disposables)
                {
                    disposable.Dispose();
                }
            }));
        }
Exemplo n.º 3
0
        public void ConnectionCanReadAndWrite(TestServiceContext testContext)
        {
            var port = TestServer.GetNextPort();

            testContext.App = App;
            var engine = new KestrelEngine(testContext);

            engine.Start(1);
            var address = ServerAddress.FromUrl($"http://localhost:{port}/");
            var started = engine.CreateServer(address);

            var socket = TestConnection.CreateConnectedLoopbackSocket(port);

            socket.Send(Encoding.ASCII.GetBytes("POST / HTTP/1.0\r\n\r\nHello World"));
            socket.Shutdown(SocketShutdown.Send);
            var buffer = new byte[8192];

            while (true)
            {
                var length = socket.Receive(buffer);
                if (length == 0)
                {
                    break;
                }
                var text = Encoding.ASCII.GetString(buffer, 0, length);
            }
            started.Dispose();
            engine.Dispose();
        }
Exemplo n.º 4
0
        public MultipleLoopTests()
        {
            var engine = new KestrelEngine(new TestServiceContext());

            _uv     = engine.Libuv;
            _logger = engine.Log;
        }
Exemplo n.º 5
0
        public void EngineCanStartAndStop()
        {
            var engine = new KestrelEngine(LibraryManager, new TestServiceContext());

            engine.Start(1);
            engine.Dispose();
        }
Exemplo n.º 6
0
        public void ProducingStartAndProducingCompleteCanBeCalledAfterConnectionClose()
        {
            var mockLibuv = new MockLibuv();

            using (var memory = new MemoryPool())
                using (var kestrelEngine = new KestrelEngine(mockLibuv, new TestServiceContext()))
                {
                    kestrelEngine.Start(count: 1);

                    var kestrelThread = kestrelEngine.Threads[0];
                    var socket        = new MockSocket(mockLibuv, kestrelThread.Loop.ThreadId, new TestKestrelTrace());
                    var trace         = new KestrelTrace(new TestKestrelTrace());
                    var ltp           = new LoggingThreadPool(trace);
                    var connection    = new MockConnection();
                    var socketOutput  = new SocketOutput(kestrelThread, socket, memory, connection, "0", trace, ltp, new Queue <UvWriteReq>());

                    // Close SocketOutput
                    var cleanupTask = socketOutput.WriteAsync(
                        default(ArraySegment <byte>), default(CancellationToken), socketDisconnect: true);

                    Assert.True(connection.SocketClosed.Wait(1000));

                    var start = socketOutput.ProducingStart();

                    Assert.True(start.IsDefault);
                    // ProducingComplete should not throw given a default iterator
                    socketOutput.ProducingComplete(start);
                }
        }
Exemplo n.º 7
0
        public async Task EngineCanStartAndStop()
        {
            var engine = new KestrelEngine(LibraryManager, new ShutdownNotImplemented());

            engine.Start(1);
            engine.Dispose();
        }
Exemplo n.º 8
0
        public void EngineCanStartAndStop(ServiceContext testContext)
        {
            var engine = new KestrelEngine(testContext);

            engine.Start(1);
            engine.Dispose();
        }
Exemplo n.º 9
0
        public void ConnectionCanReadAndWrite(TestServiceContext testContext)
        {
            testContext.App = App;
            var engine = new KestrelEngine(testContext);

            engine.Start(1);
            var address = ServerAddress.FromUrl("http://localhost:54321/");
            var started = engine.CreateServer(address);

            Console.WriteLine("Started");
            var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            socket.Connect(new IPEndPoint(IPAddress.Loopback, 54321));
            socket.Send(Encoding.ASCII.GetBytes("POST / HTTP/1.0\r\n\r\nHello World"));
            socket.Shutdown(SocketShutdown.Send);
            var buffer = new byte[8192];

            while (true)
            {
                var length = socket.Receive(buffer);
                if (length == 0)
                {
                    break;
                }
                var text = Encoding.ASCII.GetString(buffer, 0, length);
            }
            started.Dispose();
            engine.Dispose();
        }
Exemplo n.º 10
0
        public async Task ConnectionCanReadAndWrite()
        {
            var engine = new KestrelEngine(LibraryManager, new ShutdownNotImplemented());

            engine.Start(1);
            var started = engine.CreateServer("http", "localhost", 54321, App);

            Console.WriteLine("Started");
            var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            socket.Connect(new IPEndPoint(IPAddress.Loopback, 54321));
            socket.Send(Encoding.ASCII.GetBytes("POST / HTTP/1.0\r\n\r\nHello World"));
            socket.Shutdown(SocketShutdown.Send);
            var buffer = new byte[8192];

            for (; ;)
            {
                var length = socket.Receive(buffer);
                if (length == 0)
                {
                    break;
                }
                var text = Encoding.ASCII.GetString(buffer, 0, length);
            }
            started.Dispose();
            engine.Dispose();
        }
Exemplo n.º 11
0
        public void DoesNotEndConnectionOnZeroRead()
        {
            var mockLibuv = new MockLibuv();

            using (var memory = new MemoryPool())
                using (var engine = new KestrelEngine(mockLibuv, new TestServiceContext()))
                {
                    engine.Start(count: 1);

                    var trace   = new TestKestrelTrace();
                    var context = new ListenerContext(new TestServiceContext())
                    {
                        FrameFactory = connectionContext => new Frame <HttpContext>(
                            new DummyApplication(httpContext => TaskUtilities.CompletedTask), connectionContext),
                        Memory        = memory,
                        ServerAddress = ServerAddress.FromUrl($"http://localhost:{TestServer.GetNextPort()}"),
                        Thread        = engine.Threads[0]
                    };
                    var socket     = new MockSocket(mockLibuv, Thread.CurrentThread.ManagedThreadId, trace);
                    var connection = new Connection(context, socket);
                    connection.Start();

                    Libuv.uv_buf_t ignored;
                    mockLibuv.AllocCallback(socket.InternalGetHandle(), 2048, out ignored);
                    mockLibuv.ReadCallback(socket.InternalGetHandle(), 0, ref ignored);
                    Assert.False(connection.SocketInput.RemoteIntakeFin);

                    connection.ConnectionControl.End(ProduceEndType.SocketDisconnect);
                }
        }
        public NetworkingTests()
        {
            var engine = new KestrelEngine(new TestServiceContext());

            _uv     = engine.Libuv;
            _logger = engine.Log;
        }
Exemplo n.º 13
0
 public void Create(Func <IFeatureCollection, Task> app, ServiceContext context, string serverAddress)
 {
     _engine = new KestrelEngine(context);
     _engine.Start(1);
     _server = _engine.CreateServer(
         ServerAddress.FromUrl(serverAddress),
         app);
 }
Exemplo n.º 14
0
        public void OnlyAllowsUpToThreeConcurrentWrites()
        {
            var writeWh       = new ManualResetEventSlim();
            var completeQueue = new Queue <Action <int> >();

            var mockLibuv = new MockLibuv
            {
                OnWrite = (socket, buffers, triggerCompleted) =>
                {
                    writeWh.Set();
                    completeQueue.Enqueue(triggerCompleted);
                    return(0);
                }
            };

            using (var memory = new MemoryPool())
                using (var kestrelEngine = new KestrelEngine(mockLibuv, new TestServiceContext()))
                {
                    kestrelEngine.Start(count: 1);

                    var kestrelThread = kestrelEngine.Threads[0];
                    var socket        = new MockSocket(mockLibuv, kestrelThread.Loop.ThreadId, new TestKestrelTrace());
                    var trace         = new KestrelTrace(new TestKestrelTrace());
                    var ltp           = new LoggingThreadPool(trace);
                    var socketOutput  = new SocketOutput(kestrelThread, socket, memory, new MockConnection(), "0", trace, ltp, new Queue <UvWriteReq>());

                    var buffer = new ArraySegment <byte>(new byte[1]);

                    // First three writes trigger uv_write
                    socketOutput.WriteAsync(buffer, CancellationToken.None);
                    Assert.True(writeWh.Wait(1000));
                    writeWh.Reset();
                    socketOutput.WriteAsync(buffer, CancellationToken.None);
                    Assert.True(writeWh.Wait(1000));
                    writeWh.Reset();
                    socketOutput.WriteAsync(buffer, CancellationToken.None);
                    Assert.True(writeWh.Wait(1000));
                    writeWh.Reset();

                    // The fourth write won't trigger uv_write since the first three haven't completed
                    socketOutput.WriteAsync(buffer, CancellationToken.None);
                    Assert.False(writeWh.Wait(1000));

                    // Complete 1st write allowing uv_write to be triggered again
                    completeQueue.Dequeue()(0);
                    Assert.True(writeWh.Wait(1000));

                    // Cleanup
                    var cleanupTask = socketOutput.WriteAsync(
                        default(ArraySegment <byte>), default(CancellationToken), socketDisconnect: true);

                    foreach (var triggerCompleted in completeQueue)
                    {
                        triggerCompleted(0);
                    }
                }
        }
Exemplo n.º 15
0
        public void WritesAreAggregated()
        {
            var writeWh    = new ManualResetEventSlim();
            var writeCount = 0;

            var mockLibuv = new MockLibuv
            {
                OnWrite = (socket, buffers, triggerCompleted) =>
                {
                    writeCount++;
                    triggerCompleted(0);
                    writeWh.Set();
                    return(0);
                }
            };

            using (var memory = new MemoryPool())
                using (var kestrelEngine = new KestrelEngine(mockLibuv, new TestServiceContext()))
                {
                    kestrelEngine.Start(count: 1);

                    var kestrelThread = kestrelEngine.Threads[0];
                    var socket        = new MockSocket(mockLibuv, kestrelThread.Loop.ThreadId, new TestKestrelTrace());
                    var trace         = new KestrelTrace(new TestKestrelTrace());
                    var ltp           = new LoggingThreadPool(trace);
                    var socketOutput  = new SocketOutput(kestrelThread, socket, memory, new MockConnection(), "0", trace, ltp, new Queue <UvWriteReq>());

                    var blockThreadWh = new ManualResetEventSlim();
                    kestrelThread.Post(_ =>
                    {
                        blockThreadWh.Wait();
                    }, state: null);

                    var buffer = new ArraySegment <byte>(new byte[1]);

                    // Two calls to WriteAsync trigger uv_write once if both calls
                    // are made before write is scheduled
                    socketOutput.WriteAsync(buffer, CancellationToken.None);
                    socketOutput.WriteAsync(buffer, CancellationToken.None);

                    blockThreadWh.Set();

                    Assert.True(writeWh.Wait(1000));
                    writeWh.Reset();

                    // Write isn't called twice after the thread is unblocked
                    Assert.False(writeWh.Wait(1000));
                    Assert.Equal(1, writeCount);
                    // One call to ScheduleWrite + One call to Post to block the thread
                    Assert.Equal(2, mockLibuv.PostCount);

                    // Cleanup
                    var cleanupTask = socketOutput.WriteAsync(
                        default(ArraySegment <byte>), default(CancellationToken), socketDisconnect: true);
                }
        }
Exemplo n.º 16
0
        public async Task ListenerCanCreateAndDispose()
        {
            var engine = new KestrelEngine(LibraryManager, new ShutdownNotImplemented());

            engine.Start(1);
            var started = engine.CreateServer("http", "localhost", 54321, App);

            started.Dispose();
            engine.Dispose();
        }
Exemplo n.º 17
0
 public void Create(Func <Frame, Task> app)
 {
     _engine = new KestrelEngine(LibraryManager);
     _engine.Start(1);
     _server = _engine.CreateServer(
         "http",
         "localhost",
         54321,
         app);
 }
Exemplo n.º 18
0
        public void ListenerCanCreateAndDispose()
        {
            var engine = new KestrelEngine(LibraryManager, new TestServiceContext());

            engine.Start(1);
            var started = engine.CreateServer("http", "localhost", 54321, App);

            started.Dispose();
            engine.Dispose();
        }
Exemplo n.º 19
0
        public void WritesDontCompleteImmediatelyWhenTooManyBytesAreAlreadyPreCompleted()
        {
            // This should match _maxBytesPreCompleted in SocketOutput
            var maxBytesPreCompleted = 65536;
            var completeQueue        = new Queue <Action <int> >();

            // Arrange
            var mockLibuv = new MockLibuv
            {
                OnWrite = (socket, buffers, triggerCompleted) =>
                {
                    completeQueue.Enqueue(triggerCompleted);
                    return(0);
                }
            };

            using (var kestrelEngine = new KestrelEngine(mockLibuv, new TestServiceContext()))
                using (var memory = new MemoryPool2())
                {
                    kestrelEngine.Start(count: 1);

                    var kestrelThread = kestrelEngine.Threads[0];
                    var socket        = new MockSocket(kestrelThread.Loop.ThreadId, new TestKestrelTrace());
                    var trace         = new KestrelTrace(new TestKestrelTrace());
                    var ltp           = new LoggingThreadPool(trace);
                    var socketOutput  = new SocketOutput(kestrelThread, socket, memory, null, 0, trace, ltp, new Queue <UvWriteReq>());

                    var           bufferSize  = maxBytesPreCompleted;
                    var           buffer      = new ArraySegment <byte>(new byte[bufferSize], 0, bufferSize);
                    var           completedWh = new ManualResetEventSlim();
                    Action <Task> onCompleted = (Task t) =>
                    {
                        Assert.Null(t.Exception);
                        completedWh.Set();
                    };

                    // Act
                    socketOutput.WriteAsync(buffer).ContinueWith(onCompleted);
                    // Assert
                    // The first write should pre-complete since it is <= _maxBytesPreCompleted.
                    Assert.True(completedWh.Wait(1000));
                    // Arrange
                    completedWh.Reset();
                    // Act
                    socketOutput.WriteAsync(buffer).ContinueWith(onCompleted);
                    // Assert
                    // Too many bytes are already pre-completed for the second write to pre-complete.
                    Assert.False(completedWh.Wait(1000));
                    // Act
                    completeQueue.Dequeue()(0);
                    // Assert
                    // Finishing the first write should allow the second write to pre-complete.
                    Assert.True(completedWh.Wait(1000));
                }
        }
Exemplo n.º 20
0
 public void Create(RequestDelegate app, ServiceContext context, string serverAddress)
 {
     context.FrameFactory = (connectionContext, remoteEP, localEP, prepareRequest) =>
     {
         return(new Frame <HttpContext>(new DummyApplication(app), connectionContext, remoteEP, localEP, prepareRequest));
     };
     _engine = new KestrelEngine(context);
     _engine.Start(1);
     _server = _engine.CreateServer(
         ServerAddress.FromUrl(serverAddress));
 }
Exemplo n.º 21
0
        public void ListenerCanCreateAndDispose(ServiceContext testContext)
        {
            var engine = new KestrelEngine(testContext);

            engine.Start(1);
            var address = ServerAddress.FromUrl("http://localhost:54321/");
            var started = engine.CreateServer(address, App);

            started.Dispose();
            engine.Dispose();
        }
Exemplo n.º 22
0
        public void ListenerCanCreateAndDispose(TestServiceContext testContext)
        {
            testContext.App = App;
            var engine = new KestrelEngine(testContext);

            engine.Start(1);
            var address = ServerAddress.FromUrl($"http://localhost:{TestServer.GetNextPort()}/");
            var started = engine.CreateServer(address);

            started.Dispose();
            engine.Dispose();
        }
        public void ListenerCanCreateAndDispose(TestServiceContext testContext)
        {
            testContext.App = App;
            var engine = new KestrelEngine(testContext);

            engine.Start(1);
            var address = ServerAddress.FromUrl("http://127.0.0.1:0/");
            var started = engine.CreateServer(address);

            started.Dispose();
            engine.Dispose();
        }
Exemplo n.º 24
0
        public void ProducingStartAndProducingCompleteCanBeUsedDirectly()
        {
            int nBuffers  = 0;
            var nBufferWh = new ManualResetEventSlim();

            var mockLibuv = new MockLibuv
            {
                OnWrite = (socket, buffers, triggerCompleted) =>
                {
                    nBuffers = buffers;
                    nBufferWh.Set();
                    triggerCompleted(0);
                    return(0);
                }
            };

            using (var memory = new MemoryPool())
                using (var kestrelEngine = new KestrelEngine(mockLibuv, new TestServiceContext()))
                {
                    kestrelEngine.Start(count: 1);

                    var kestrelThread = kestrelEngine.Threads[0];
                    var socket        = new MockSocket(mockLibuv, kestrelThread.Loop.ThreadId, new TestKestrelTrace());
                    var trace         = new KestrelTrace(new TestKestrelTrace());
                    var ltp           = new LoggingThreadPool(trace);
                    var socketOutput  = new SocketOutput(kestrelThread, socket, memory, new MockConnection(), "0", trace, ltp, new Queue <UvWriteReq>());

                    // block 1
                    var start = socketOutput.ProducingStart();
                    start.Block.End = start.Block.Data.Offset + start.Block.Data.Count;

                    // block 2
                    var block2 = memory.Lease();
                    block2.End       = block2.Data.Offset + block2.Data.Count;
                    start.Block.Next = block2;

                    var end = new MemoryPoolIterator(block2, block2.End);

                    socketOutput.ProducingComplete(end);

                    // A call to Write is required to ensure a write is scheduled
                    socketOutput.WriteAsync(default(ArraySegment <byte>), default(CancellationToken));

                    Assert.True(nBufferWh.Wait(1000));
                    Assert.Equal(2, nBuffers);

                    // Cleanup
                    var cleanupTask = socketOutput.WriteAsync(
                        default(ArraySegment <byte>), default(CancellationToken), socketDisconnect: true);
                }
        }
Exemplo n.º 25
0
        public void CanWrite1MB()
        {
            // This test was added because when initially implementing write-behind buffering in
            // SocketOutput, the write callback would never be invoked for writes larger than
            // _maxBytesPreCompleted even after the write actually completed.

            // Arrange
            var mockLibuv = new MockLibuv
            {
                OnWrite = (socket, buffers, triggerCompleted) =>
                {
                    triggerCompleted(0);
                    return(0);
                }
            };

            using (var memory = new MemoryPool())
                using (var kestrelEngine = new KestrelEngine(mockLibuv, new TestServiceContext()))
                {
                    kestrelEngine.Start(count: 1);

                    var kestrelThread = kestrelEngine.Threads[0];
                    var socket        = new MockSocket(mockLibuv, kestrelThread.Loop.ThreadId, new TestKestrelTrace());
                    var trace         = new KestrelTrace(new TestKestrelTrace());
                    var ltp           = new LoggingThreadPool(trace);
                    var socketOutput  = new SocketOutput(kestrelThread, socket, memory, new MockConnection(), "0", trace, ltp, new Queue <UvWriteReq>());

                    // I doubt _maxBytesPreCompleted will ever be over a MB. If it is, we should change this test.
                    var bufferSize  = 1048576;
                    var buffer      = new ArraySegment <byte>(new byte[bufferSize], 0, bufferSize);
                    var completedWh = new ManualResetEventSlim();

                    // Act
                    socketOutput.WriteAsync(buffer, default(CancellationToken)).ContinueWith(
                        (t) =>
                    {
                        Assert.Null(t.Exception);
                        completedWh.Set();
                    }
                        );

                    // Assert
                    Assert.True(completedWh.Wait(1000));

                    // Cleanup
                    var cleanupTask = socketOutput.WriteAsync(
                        default(ArraySegment <byte>), default(CancellationToken), socketDisconnect: true);
                }
        }
        public void ConsumingCompleteCallsBufferSizeControlSubtract(Mock <IBufferSizeControl> mockBufferSizeControl)
        {
            using (var kestrelEngine = new KestrelEngine(new MockLibuv(), new TestServiceContext()))
            {
                kestrelEngine.Start(1);

                using (var memory = new MemoryPool())
                    using (var socketInput = new SocketInput(memory, null, mockBufferSizeControl?.Object))
                    {
                        socketInput.IncomingData(new byte[20], 0, 20);

                        var iterator = socketInput.ConsumingStart();
                        iterator.Skip(5);
                        socketInput.ConsumingComplete(iterator, iterator);
                        mockBufferSizeControl?.Verify(b => b.Subtract(5));
                    }
            }
        }
Exemplo n.º 27
0
        public void CanWrite1MB()
        {
            // This test was added because when initially implementing write-behind buffering in
            // SocketOutput, the write callback would never be invoked for writes larger than
            // _maxBytesPreCompleted even after the write actually completed.

            // Arrange
            var mockLibuv = new MockLibuv
            {
                OnWrite = (socket, buffers, triggerCompleted) =>
                {
                    triggerCompleted(0);
                    return(0);
                }
            };

            using (var kestrelEngine = new KestrelEngine(mockLibuv, new TestServiceContext()))
            {
                kestrelEngine.Start(count: 1);

                var kestrelThread = kestrelEngine.Threads[0];
                var socket        = new MockSocket(kestrelThread.Loop.ThreadId, new TestKestrelTrace());
                var trace         = new KestrelTrace(new TestKestrelTrace());
                var socketOutput  = new SocketOutput(kestrelThread, socket, 0, trace);

                // I doubt _maxBytesPreCompleted will ever be over a MB. If it is, we should change this test.
                var bufferSize  = 1048576;
                var buffer      = new ArraySegment <byte>(new byte[bufferSize], 0, bufferSize);
                var completedWh = new ManualResetEventSlim();
                Action <Exception, object, bool> onCompleted = (ex, state, calledInline) =>
                {
                    Assert.Null(ex);
                    Assert.Null(state);
                    completedWh.Set();
                };

                // Act
                socketOutput.Write(buffer, onCompleted, null);

                // Assert
                Assert.True(completedWh.Wait(1000));
            }
        }
Exemplo n.º 28
0
        public TestServer(RequestDelegate app, ServiceContext context, string serverAddress)
        {
            context.FrameFactory = connectionContext =>
            {
                return(new Frame <HttpContext>(new DummyApplication(app), connectionContext));
            };

            try
            {
                _engine = new KestrelEngine(context);
                _engine.Start(1);
                _address = ServerAddress.FromUrl(serverAddress);
                _server  = _engine.CreateServer(_address);
            }
            catch
            {
                _server?.Dispose();
                _engine?.Dispose();
                throw;
            }
        }
Exemplo n.º 29
0
        public NetworkingTests()
        {
            var engine = new KestrelEngine(LibraryManager);

            _uv = engine.Libuv;
        }
Exemplo n.º 30
0
        public void WritesDontGetCompletedTooQuickly()
        {
            // This should match _maxBytesPreCompleted in SocketOutput
            var maxBytesPreCompleted = 65536;
            var completeQueue        = new Queue <Action <int> >();
            var onWriteWh            = new ManualResetEventSlim();

            // Arrange
            var mockLibuv = new MockLibuv
            {
                OnWrite = (socket, buffers, triggerCompleted) =>
                {
                    completeQueue.Enqueue(triggerCompleted);
                    onWriteWh.Set();

                    return(0);
                }
            };

            using (var memory = new MemoryPool())
                using (var kestrelEngine = new KestrelEngine(mockLibuv, new TestServiceContext()))
                {
                    kestrelEngine.Start(count: 1);

                    var kestrelThread = kestrelEngine.Threads[0];
                    var socket        = new MockSocket(mockLibuv, kestrelThread.Loop.ThreadId, new TestKestrelTrace());
                    var trace         = new KestrelTrace(new TestKestrelTrace());
                    var ltp           = new LoggingThreadPool(trace);
                    var socketOutput  = new SocketOutput(kestrelThread, socket, memory, new MockConnection(), "0", trace, ltp, new Queue <UvWriteReq>());

                    var bufferSize = maxBytesPreCompleted;
                    var buffer     = new ArraySegment <byte>(new byte[bufferSize], 0, bufferSize);

                    var           completedWh = new ManualResetEventSlim();
                    Action <Task> onCompleted = (Task t) =>
                    {
                        Assert.Null(t.Exception);
                        completedWh.Set();
                    };

                    var           completedWh2 = new ManualResetEventSlim();
                    Action <Task> onCompleted2 = (Task t) =>
                    {
                        Assert.Null(t.Exception);
                        completedWh2.Set();
                    };

                    // Act (Pre-complete the maximum number of bytes in preparation for the rest of the test)
                    socketOutput.WriteAsync(buffer, default(CancellationToken)).ContinueWith(onCompleted);
                    // Assert
                    // The first write should pre-complete since it is <= _maxBytesPreCompleted.
                    Assert.True(completedWh.Wait(1000));
                    Assert.True(onWriteWh.Wait(1000));
                    // Arrange
                    completedWh.Reset();
                    onWriteWh.Reset();

                    // Act
                    socketOutput.WriteAsync(buffer, default(CancellationToken)).ContinueWith(onCompleted);
                    socketOutput.WriteAsync(buffer, default(CancellationToken)).ContinueWith(onCompleted2);

                    Assert.True(onWriteWh.Wait(1000));
                    completeQueue.Dequeue()(0);

                    // Assert
                    // Too many bytes are already pre-completed for the third but not the second write to pre-complete.
                    // https://github.com/aspnet/KestrelHttpServer/issues/356
                    Assert.True(completedWh.Wait(1000));
                    Assert.False(completedWh2.Wait(1000));

                    // Act
                    completeQueue.Dequeue()(0);

                    // Assert
                    // Finishing the first write should allow the second write to pre-complete.
                    Assert.True(completedWh2.Wait(1000));

                    // Cleanup
                    var cleanupTask = ((SocketOutput)socketOutput).WriteAsync(
                        default(ArraySegment <byte>), default(CancellationToken), socketDisconnect: true);

                    foreach (var triggerCompleted in completeQueue)
                    {
                        triggerCompleted(0);
                    }
                }
        }