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); } }
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 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); } } }