public async Task CreateChannel_InputPipeOptions() { const int DataSize = 1024 * 1024; var channelOptions = new MultiplexingStream.ChannelOptions { InputPipeOptions = new PipeOptions(pauseWriterThreshold: 2 * 1024 * 1024), }; var channel1 = this.mx1.CreateChannel(channelOptions); // Blast a bunch of data to the channel as soon as it is accepted. await this.WaitForEphemeralChannelOfferToPropagate(); var channel2 = this.mx2.AcceptChannel(channel1.Id, channelOptions); await channel2.Output.WriteAsync(new byte[DataSize], this.TimeoutToken); // Read all the data, such that the PipeReader has to buffer until the whole payload is read. // Since this is a LOT of data, this would normally overrun the Pipe's max buffer size. // If this succeeds, then we know the PipeOptions instance we supplied was taken into account. int bytesRead = 0; while (bytesRead < DataSize) { var readResult = await channel1.Input.ReadAsync(this.TimeoutToken); bytesRead += (int)readResult.Buffer.Length; SequencePosition consumed = bytesRead == DataSize ? readResult.Buffer.End : readResult.Buffer.Start; channel1.Input.AdvanceTo(consumed, readResult.Buffer.End); } }
public void Defaults() { var options = new MultiplexingStream.ChannelOptions(); Assert.Null(options.TraceSource); Assert.Null(options.ExistingPipe); }
public async Task AcceptChannel_InputPipeOptions(bool acceptBeforeTransmit) { // We have to use a smaller data size when transmitting before acceptance to avoid a deadlock due to the limited buffer size of channels. int dataSize = acceptBeforeTransmit ? 1024 * 1024 : 16 * 1024; var channelOptions = new MultiplexingStream.ChannelOptions { InputPipeOptions = new PipeOptions(pauseWriterThreshold: 2 * 1024 * 1024), }; var channel1 = this.mx1.CreateChannel(); await this.WaitForEphemeralChannelOfferToPropagateAsync(); var bytesWrittenEvent = new AsyncManualResetEvent(); await Task.WhenAll(Party1Async(), Party2Async()); async Task Party1Async() { if (acceptBeforeTransmit) { await channel1.Acceptance.WithCancellation(this.TimeoutToken); } await channel1.Output.WriteAsync(new byte[dataSize], this.TimeoutToken); bytesWrittenEvent.Set(); } async Task Party2Async() { if (!acceptBeforeTransmit) { await bytesWrittenEvent.WaitAsync(this.TimeoutToken); } var channel2 = this.mx2.AcceptChannel(channel1.Id, channelOptions); // Read all the data, such that the PipeReader has to buffer until the whole payload is read. // Since this is a LOT of data, this would normally overrun the Pipe's max buffer size. // If this succeeds, then we know the PipeOptions instance we supplied was taken into account. int bytesRead = 0; while (bytesRead < dataSize) { var readResult = await channel2.Input.ReadAsync(this.TimeoutToken); bytesRead += (int)readResult.Buffer.Length; SequencePosition consumed = bytesRead == dataSize ? readResult.Buffer.End : readResult.Buffer.Start; channel2.Input.AdvanceTo(consumed, readResult.Buffer.End); } } }
public void ReaderPipeOptions() { PipeOptions expected = new PipeOptions(); var options = new MultiplexingStream.ChannelOptions { InputPipeOptions = expected, }; Assert.Same(expected, options.InputPipeOptions); options.InputPipeOptions = null; Assert.Null(options.InputPipeOptions); }
public void TraceSource() { var src = new TraceSource("name"); var options = new MultiplexingStream.ChannelOptions { TraceSource = src, }; Assert.Same(src, options.TraceSource); options.TraceSource = null; Assert.Null(options.TraceSource); }
public void ExistingPipe_AcceptsSimplex() { var options = new MultiplexingStream.ChannelOptions(); var pipe = new Pipe(); Assert.Throws <ArgumentException>(() => options.ExistingPipe = new MockDuplexPipe()); options.ExistingPipe = new MockDuplexPipe { Input = pipe.Reader }; options.ExistingPipe = new MockDuplexPipe { Output = pipe.Writer }; }
public void ExistingPipe_DuplexPipe() { var pipe = new Pipe(); var duplexPipe = new DuplexPipe(pipe.Reader, pipe.Writer); var options = new MultiplexingStream.ChannelOptions { ExistingPipe = duplexPipe, }; // We provided an instance of the concrete type DuplexPipe, so we expect that instance was persisted. Assert.Same(duplexPipe, options.ExistingPipe); options.ExistingPipe = null; Assert.Null(options.ExistingPipe); }
public void ExistingPipe_AcceptsSimplex() { var options = new MultiplexingStream.ChannelOptions(); // This was designed before nullable annotations on the IDuplexPipe determined that both properties should always be non-null. var pipe = new Pipe(); Assert.Throws <ArgumentException>(() => options.ExistingPipe = new MockDuplexPipe()); options.ExistingPipe = new MockDuplexPipe { Input = pipe.Reader }; options.ExistingPipe = new MockDuplexPipe { Output = pipe.Writer }; }
public async Task ExistingPipe_Send_Accept_Send() { var packets = new byte[][] { new byte[] { 1, 2, 3 }, new byte[] { 4, 5, 6 }, }; var emptyReaderPipe = new Pipe(); emptyReaderPipe.Writer.Complete(); var slowWriter = new SlowPipeWriter(); var channel2Options = new MultiplexingStream.ChannelOptions { ExistingPipe = new DuplexPipe(emptyReaderPipe.Reader, slowWriter), }; // Create the channel and transmit before it is accepted. var channel1 = this.mx1.CreateChannel(); var channel1Stream = channel1.AsStream(); await channel1Stream.WriteAsync(packets[0], 0, packets[0].Length, this.TimeoutToken); await channel1Stream.FlushAsync(this.TimeoutToken); // Accept the channel await this.WaitForEphemeralChannelOfferToPropagate(); var channel2 = this.mx2.AcceptChannel(channel1.Id, channel2Options); // Send MORE bytes await channel1Stream.WriteAsync(packets[1], 0, packets[1].Length, this.TimeoutToken); await channel1Stream.FlushAsync(this.TimeoutToken); // Allow the copying of the first packet to our ExistingPipe to complete. slowWriter.UnblockGetMemory.Set(); // Wait for all bytes to be transmitted channel1.Output.Complete(); await slowWriter.Completion; // Verify that we received them all, in order. Assert.Equal(packets[0].Concat(packets[1]).ToArray(), slowWriter.WrittenBytes.ToArray()); }
public void ExistingPipe_Mock() { var pipe = new Pipe(); var duplexPipe = new MockDuplexPipe { Input = pipe.Reader, Output = pipe.Writer }; var options = new MultiplexingStream.ChannelOptions { ExistingPipe = duplexPipe, }; // We provided an "untrusted" instance of IDuplexPipe, so it would be copied into a trusted type. // Only assert that the contents are the same. Assert.Same(duplexPipe.Input, options.ExistingPipe.Input); Assert.Same(duplexPipe.Output, options.ExistingPipe.Output); options.ExistingPipe = null; Assert.Null(options.ExistingPipe); }
public async Task OfferChannelAsync_WithExistingPipe() { var channel2OutboundPipe = new Pipe(); var channel2InboundPipe = new Pipe(); var channel2Stream = new DuplexPipe(channel2InboundPipe.Reader, channel2OutboundPipe.Writer).AsStream(); var channel2Options = new MultiplexingStream.ChannelOptions { ExistingPipe = new DuplexPipe(channel2OutboundPipe.Reader, channel2InboundPipe.Writer) }; const string channelName = "channelName"; var mx2ChannelTask = this.mx2.OfferChannelAsync(channelName, channel2Options, this.TimeoutToken); var mx1ChannelTask = this.mx1.AcceptChannelAsync(channelName, this.TimeoutToken); var channels = await Task.WhenAll(mx1ChannelTask, mx2ChannelTask).WithCancellation(this.TimeoutToken); var channel1Stream = channels[0].AsStream(); await this.TransmitAndVerifyAsync(channel1Stream, channel2Stream, new byte[] { 1, 2, 3 }); await this.TransmitAndVerifyAsync(channel2Stream, channel1Stream, new byte[] { 4, 5, 6 }); }
public async Task ExistingPipe_Send_Accept_Recv_Send() { var packets = new byte[][] { new byte[] { 1, 2, 3 }, new byte[] { 4, 5, 6 }, new byte[] { 7, 8, 9 }, }; var channel2OutboundPipe = new Pipe(); var channel2InboundPipe = new Pipe(); var channel2Stream = new DuplexPipe(channel2InboundPipe.Reader, channel2OutboundPipe.Writer).AsStream(); var channel2Options = new MultiplexingStream.ChannelOptions { ExistingPipe = new DuplexPipe(channel2OutboundPipe.Reader, channel2InboundPipe.Writer) }; // Create the channel and transmit before it is accepted. var channel1 = this.mx1.CreateChannel(); var channel1Stream = channel1.AsStream(); await channel1Stream.WriteAsync(packets[0], 0, packets[0].Length, this.TimeoutToken); await channel1Stream.FlushAsync(this.TimeoutToken); // Accept the channel and read the bytes await this.WaitForEphemeralChannelOfferToPropagate(); var channel2 = this.mx2.AcceptChannel(channel1.Id, channel2Options); await this.VerifyReceivedDataAsync(channel2Stream, packets[0]); // Verify we can transmit via the ExistingPipe. await this.TransmitAndVerifyAsync(channel2Stream, channel1Stream, packets[1]); // Verify we can receive more bytes via the ExistingPipe. // MANUALLY VERIFY with debugger that received bytes are read DIRECTLY into channel2InboundPipe.Writer (no intermediary buffer copying). await this.TransmitAndVerifyAsync(channel1Stream, channel2Stream, packets[2]); }