Ejemplo n.º 1
0
    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);
    }
Ejemplo n.º 3
0
    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
        };
    }
Ejemplo n.º 9
0
    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);
    }
Ejemplo n.º 11
0
    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 });
    }
Ejemplo n.º 12
0
    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]);
    }