public async Task StreamWindowUpdatesShouldRespectBufferState() { var inPipe = new BufferedPipe(1024); var outPipe = new BufferedPipe(1024); // Lower the initial window size so that stream window updates are // sent earlier than connection window updates var settings = Settings.Default; settings.InitialWindowSize = 16000; settings.MaxFrameSize = 1000000; var res = await ServerStreamTests.StreamCreator.CreateConnectionAndStream( StreamState.Open, loggerProvider, inPipe, outPipe, localSettings : settings); // Write 12k of data. Buffer amount: 12k. Remaining window: 4k await inPipe.WriteData(1u, 12000); // Read 5k of data. Buffer amount: 7k await res.stream.ReadAllWithTimeout(new ArraySegment <byte>(new byte[5000])); // This should not trigger a window update await inPipe.WritePing(new byte[8], false); await outPipe.ReadAndDiscardPong(); // Read 5k of data. Buffer amount: 2k await res.stream.ReadAllWithTimeout(new ArraySegment <byte>(new byte[5000])); // Expect a window update of 10k. Remaining window: 14k await outPipe.AssertWindowUpdate(1u, 10000); // Read 2k of data - buffer is now drained await res.stream.ReadAllWithTimeout(new ArraySegment <byte>(new byte[2000])); // This should not trigger a window update await inPipe.WritePing(new byte[8], false); await outPipe.ReadAndDiscardPong(); // Write 4k of data. Buffer amount: 4k. Remaining window: 10k await inPipe.WriteData(1u, 4000); // Read 4k of data. Buffer amount: 0k await res.stream.ReadAllWithTimeout(new ArraySegment <byte>(new byte[4000])); // This should not trigger a window update await inPipe.WritePing(new byte[8], false); await outPipe.ReadAndDiscardPong(); // Write 8k of data. Buffer amount: 8k. Remaining window: 2k await inPipe.WriteData(1u, 8000); // Read 5k of data. Buffer amount: 3k await res.stream.ReadAllWithTimeout(new ArraySegment <byte>(new byte[5000])); // Expect a window update of 11k. Remaining window: 13k await outPipe.AssertWindowUpdate(1u, 11000); }
public async Task SendingLargeAmountOfDataShouldTriggerWindowUpdates( int[] dataLength, int[] expectedStreamWindowUpdates, int[] expectedConnWindowUpdates) { var inPipe = new BufferedPipe(1024); var outPipe = new BufferedPipe(1024); // Lower the initial window size so that stream window updates are // sent earlier than connection window updates var settings = Settings.Default; settings.InitialWindowSize = 16000; var res = await ServerStreamTests.StreamCreator.CreateConnectionAndStream( StreamState.Open, loggerProvider, inPipe, outPipe, localSettings : settings); // Consume all data on reader side var readTask = Task.Run(async() => { await res.stream.ReadHeadersAsync(); var data = await res.stream.ReadAllToArrayWithTimeout(); }); for (var i = 0; i < dataLength.Length; i++) { var toSend = dataLength[i]; var isEndOfStream = i == (dataLength.Length - 1); await inPipe.WriteData(1u, toSend, endOfStream : isEndOfStream); // Wait for a short amount of time between DATA frames if (!isEndOfStream) { await Task.Delay(5); } // Check if window updates were received if required if (expectedConnWindowUpdates[i] != 0) { await outPipe.AssertWindowUpdate(0, expectedConnWindowUpdates[i]); } if (expectedStreamWindowUpdates[i] != 0) { await outPipe.AssertWindowUpdate(1, expectedStreamWindowUpdates[i]); } } }
public async Task ViolationsOfTheConnectionFlowControlWindowShouldBeDetected( int?padLen, uint streamId, int dataAmount, bool isError) { var inPipe = new BufferedPipe(1024); var outPipe = new BufferedPipe(1024); // Use a bigger flow control window for streams so that the connection // window errors and streams dont send window updates. // Also update maxFrameSize, otherwise the connection will send // window updates faster than we can violate the contract var settings = Settings.Default; settings.InitialWindowSize = 256 * 1024; settings.MaxFrameSize = 1024 * 1024; var res = await ServerStreamTests.StreamCreator.CreateConnectionAndStream( StreamState.Open, loggerProvider, inPipe, outPipe, localSettings : settings); // Open an additional stream, so that streamId 3 is not in the IDLE // range, which causes a connection error await inPipe.WriteHeaders( res.hEncoder, 555u, false, DefaultGetHeaders); // Try to send the data // This might fail, if the connection goes away before // everything is read try { await inPipe.WriteData(streamId, dataAmount, padLen : padLen); } catch (Exception e) { if (!isError || !(e is TimeoutException)) { throw; } } if (isError) { await outPipe.AssertGoAwayReception(ErrorCode.FlowControlError, 555u); await outPipe.AssertStreamEnd(); await res.conn.Done; Assert.Equal(StreamState.Reset, res.stream.State); } else { // Expect the connection to be alive await outPipe.AssertWindowUpdate(0u, 65535); if (streamId != 1) { // We expect a reset for the unknown stream on which data // was transmitted await outPipe.AssertResetStreamReception(streamId, ErrorCode.StreamClosed); } await inPipe.WritePing(new byte[8], false); await outPipe.ReadAndDiscardPong(); Assert.Equal(StreamState.Open, res.stream.State); } }