private void OnOutputDragDroppedTo(SocketInput target) { // if sockets connected already // do nothing if (_currentDraggingSocket.HasConnection() && target.HasConnection()) { if (_currentDraggingSocket.connection == target.connection) { _currentDraggingSocket = null; drawer.CancelDrag(); return; } } if (target != null) { // check if input allows multiple connection if (target.HasConnection()) { // disconnect old connection if (target.connectionType != ConnectionType.Multiple) { Disconnect(target.connection); } } Connect(target, _currentDraggingSocket); } _currentDraggingSocket = null; drawer.CancelDrag(); }
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); } }
private void OnOutputSocketClicked(SocketOutput output, PointerEventData eventData) { if (eventData.button == PointerEventData.InputButton.Right) { connections.Where(conn => conn.output == output) .ToList() .ForEach(conn => Disconnect(conn)); } }
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); } } }
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); } }
private static void Main(string[] args) { var server = new SocketOutput(); server.SetupServer(); server.SetupAdminServer(); Console.ReadLine(); server.CloseConnection(); Console.ReadKey(); }
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)); } }
/// <summary> /// Writes some data to the connection. /// </summary> public void Write(ArraySegment <byte> data) { // Update the expires timer this.Expires = Timer.Now + Timeout; // Increment the counters NetStat.BytesOutgoing.Add(data.Count); // Write through the socket SocketOutput.Write(data); }
/// <summary> /// Writes some data to the connection. /// </summary> public Task WriteAsync(ArraySegment <byte> data, CancellationToken cancellationToken) { // Update the expires timer this.Expires = Timer.Now + Timeout; // Increment the counters NetStat.BytesOutgoing.Add(data.Count); // Write through the socket return(SocketOutput.WriteAsync(data, cancellationToken: cancellationToken)); }
/// <summary> /// Creates a new connection from the listener context. /// </summary> /// <param name="context">The listener context to use.</param> /// <param name="socket">The socket handle.</param> internal Connection(ListenerContext context, UvStreamHandle socket) : base(context) { _socket = socket; socket.Connection = this; ConnectionId = ConnectionId.NewConnectionId(); _rawSocketInput = new SocketInput(Memory, ThreadPool); _rawSocketOutput = new SocketOutput(Thread, _socket, Memory, this, ConnectionId, ThreadPool, WriteReqPool); this.Expires = Timer.Now + TimeSpan.FromMinutes(1); this.ConnectionManager.Register(this); }
public void Post(Action <SocketOutput> callback, SocketOutput state) { lock (_workSync) { _workAdding.Enqueue(new Work { CallbackAdapter = _socketCallbackAdapter, Callback = callback, State = state }); } _post.Send(); }
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); } }
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); } }
private void OnOutputDragStarted(SocketOutput socketOnDrag) { _currentDraggingSocket = socketOnDrag; drawer.StartDrag(_currentDraggingSocket); // check socket connection type if (_currentDraggingSocket.HasConnection()) { // if single, disconnect if (_currentDraggingSocket.connectionType == ConnectionType.Single) { Disconnect(_currentDraggingSocket.connection); } } }
//public static readonly Logger.Logger Logger = new Logger.Logger(Output.Output.Socket); private static void Main(string[] args) { //Logger.Log(LogLevel.Info, "TEST 1"); //Logger.Log(LogLevel.Error, "TEST 1"); //Logger.Log(LogLevel.Alert, "TEST 1"); //Logger.Log(LogLevel.Debug, ""); var server = new SocketOutput(); server.SetupServer(); server.SetupAdminServer(); Console.ReadLine(); server.CloseConnection(); Console.ReadKey(); }
public void Connect(SocketInput input, SocketOutput output) { var connection = new Connection() { id = CreateId, input = input, output = output }; input.Connect(connection); output.Connect(connection); connections.Add(connection); input.parentNode.OnConnection(input, output); drawer.Add(connection.id, output.handle, input.handle); }
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)); } }
public async Task FailedWriteCompletesOrCancelsAllPendingTasks() { // 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 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); using (var mockConnection = new MockConnection()) { var abortedSource = mockConnection.RequestAbortedSource; ISocketOutput socketOutput = new SocketOutput(kestrelThread, socket, memory, mockConnection, "0", trace, ltp, new Queue <UvWriteReq>()); var bufferSize = maxBytesPreCompleted; var data = new byte[bufferSize]; var fullBuffer = new ArraySegment <byte>(data, 0, bufferSize); // Act var task1Success = socketOutput.WriteAsync(fullBuffer, cancellationToken: abortedSource.Token); // task1 should complete successfully as < _maxBytesPreCompleted // First task is completed and successful Assert.True(task1Success.IsCompleted); Assert.False(task1Success.IsCanceled); Assert.False(task1Success.IsFaulted); // following tasks should wait. var task2Success = socketOutput.WriteAsync(fullBuffer, cancellationToken: default(CancellationToken)); var task3Canceled = socketOutput.WriteAsync(fullBuffer, cancellationToken: abortedSource.Token); // Give time for tasks to percolate await Task.Delay(1000); // Second task is not completed Assert.False(task2Success.IsCompleted); Assert.False(task2Success.IsCanceled); Assert.False(task2Success.IsFaulted); // Third task is not completed Assert.False(task3Canceled.IsCompleted); Assert.False(task3Canceled.IsCanceled); Assert.False(task3Canceled.IsFaulted); // Cause the first write to fail. completeQueue.Dequeue()(-1); // Second task is now completed await task2Success; // Third task is now canceled await Assert.ThrowsAsync <TaskCanceledException>(() => task3Canceled); Assert.True(task3Canceled.IsCanceled); // Cleanup var cleanupTask = ((SocketOutput)socketOutput).WriteAsync( default(ArraySegment <byte>), default(CancellationToken), socketDisconnect: true); foreach (var triggerCompleted in completeQueue) { triggerCompleted(0); } } } }
public static void InvokeOutputSocketClick(SocketOutput output, PointerEventData eventData) { OutputSocketClickEvent?.Invoke(output, eventData); }
/// <summary> /// Flushes the connection. /// </summary> public async Task FlushAsync(CancellationToken cancellationToken) { await SocketOutput.WriteAsync(EmptyBuffer, cancellationToken : cancellationToken); }
/// <summary> /// Flushes the connection. /// </summary> public void Flush() { SocketOutput.Write(EmptyBuffer); }
public async Task OnlyWritesRequestingCancellationAreErroredOnCancellation() { // 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 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); using (var mockConnection = new MockConnection()) { ISocketOutput socketOutput = new SocketOutput(kestrelThread, socket, memory, mockConnection, "0", trace, ltp, new Queue <UvWriteReq>()); var bufferSize = maxBytesPreCompleted; var data = new byte[bufferSize]; var fullBuffer = new ArraySegment <byte>(data, 0, bufferSize); var cts = new CancellationTokenSource(); // Act var task1Success = socketOutput.WriteAsync(fullBuffer, cancellationToken: cts.Token); // task1 should complete successfully as < _maxBytesPreCompleted // First task is completed and successful Assert.True(task1Success.IsCompleted); Assert.False(task1Success.IsCanceled); Assert.False(task1Success.IsFaulted); // following tasks should wait. var task2Throw = socketOutput.WriteAsync(fullBuffer, cancellationToken: cts.Token); var task3Success = socketOutput.WriteAsync(fullBuffer, cancellationToken: default(CancellationToken)); // Give time for tasks to percolate await Task.Delay(1000); // Second task is not completed Assert.False(task2Throw.IsCompleted); Assert.False(task2Throw.IsCanceled); Assert.False(task2Throw.IsFaulted); // Third task is not completed Assert.False(task3Success.IsCompleted); Assert.False(task3Success.IsCanceled); Assert.False(task3Success.IsFaulted); cts.Cancel(); // Second task is now canceled await Assert.ThrowsAsync <TaskCanceledException>(() => task2Throw); Assert.True(task2Throw.IsCanceled); // Third task is now completed await task3Success; // Fourth task immediately cancels as the token is canceled var task4Throw = socketOutput.WriteAsync(fullBuffer, cancellationToken: cts.Token); Assert.True(task4Throw.IsCompleted); Assert.True(task4Throw.IsCanceled); Assert.False(task4Throw.IsFaulted); var task5Success = socketOutput.WriteAsync(fullBuffer, cancellationToken: default(CancellationToken)); // task5 should complete immediately Assert.True(task5Success.IsCompleted); Assert.False(task5Success.IsCanceled); Assert.False(task5Success.IsFaulted); cts = new CancellationTokenSource(); var task6Success = socketOutput.WriteAsync(fullBuffer, cancellationToken: cts.Token); // task6 should complete immediately but not cancel as its cancellation token isn't set Assert.True(task6Success.IsCompleted); Assert.False(task6Success.IsCanceled); Assert.False(task6Success.IsFaulted); Assert.True(true); // Cleanup var cleanupTask = ((SocketOutput)socketOutput).WriteAsync( default(ArraySegment <byte>), default(CancellationToken), socketDisconnect: true); foreach (var triggerCompleted in completeQueue) { triggerCompleted(0); } } } }
public void WritesDontCompleteImmediatelyWhenTooManyBytesIncludingNonImmediateAreAlreadyPreCompleted() { // This should match _maxBytesPreCompleted in SocketOutput var maxBytesPreCompleted = 65536; var completeQueue = new Queue <Action <int> >(); var writeRequestedWh = new ManualResetEventSlim(); // Arrange var mockLibuv = new MockLibuv { OnWrite = (socket, buffers, triggerCompleted) => { completeQueue.Enqueue(triggerCompleted); writeRequestedWh.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 / 2; var data = new byte[bufferSize]; var halfWriteBehindBuffer = new ArraySegment <byte>(data, 0, bufferSize); // Act var writeTask1 = socketOutput.WriteAsync(halfWriteBehindBuffer, default(CancellationToken)); // Assert // The first write should pre-complete since it is <= _maxBytesPreCompleted. Assert.Equal(TaskStatus.RanToCompletion, writeTask1.Status); Assert.True(writeRequestedWh.Wait(1000)); writeRequestedWh.Reset(); // Add more bytes to the write-behind buffer to prevent the next write from var iter = socketOutput.ProducingStart(); iter.CopyFrom(halfWriteBehindBuffer); socketOutput.ProducingComplete(iter); // Act var writeTask2 = socketOutput.WriteAsync(halfWriteBehindBuffer, default(CancellationToken)); // Assert // Too many bytes are already pre-completed for the fourth write to pre-complete. Assert.True(writeRequestedWh.Wait(1000)); Assert.False(writeTask2.IsCompleted); // 2 calls have been made to uv_write Assert.Equal(2, completeQueue.Count); // Act completeQueue.Dequeue()(0); // Assert // Finishing the first write should allow the second write to pre-complete. Assert.True(writeTask2.Wait(1000)); // Cleanup var cleanupTask = socketOutput.WriteAsync( default(ArraySegment <byte>), default(CancellationToken), socketDisconnect: true); foreach (var triggerCompleted in completeQueue) { triggerCompleted(0); } } }
public static void InvokeSocketDragFrom(SocketOutput output) { OutputSocketDragStartEvent?.Invoke(output); }
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); } } }