Ejemplo n.º 1
0
    public async Task BidirectionalStream_ClientAbortWrite_ServerReceivesAbort()
    {
        // Arrange
        await using var connectionListener = await QuicTestHelpers.CreateConnectionListenerFactory(LoggerFactory);

        var options = QuicTestHelpers.CreateClientConnectionOptions(connectionListener.EndPoint);

        await using var quicConnection = await QuicConnection.ConnectAsync(options);

        await using var serverConnection = await connectionListener.AcceptAndAddFeatureAsync().DefaultTimeout();

        // Act
        await using var clientStream = await quicConnection.OpenOutboundStreamAsync(QuicStreamType.Bidirectional);

        await clientStream.WriteAsync(TestData).DefaultTimeout();

        await using var serverStream = await serverConnection.AcceptAsync().DefaultTimeout();

        var readResult = await serverStream.Transport.Input.ReadAtLeastAsync(TestData.Length).DefaultTimeout();

        serverStream.Transport.Input.AdvanceTo(readResult.Buffer.End);

        var closedTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);

        serverStream.ConnectionClosed.Register(() => closedTcs.SetResult());

        clientStream.Abort(QuicAbortDirection.Write, (long)Http3ErrorCode.InternalError);

        // Receive abort from client.
        var ex = await Assert.ThrowsAsync <ConnectionResetException>(() => serverStream.Transport.Input.ReadAsync().AsTask()).DefaultTimeout();

        // Server completes its output.
        await serverStream.Transport.Output.CompleteAsync();

        // Assert
        Assert.Equal((long)Http3ErrorCode.InternalError, ((QuicException)ex.InnerException).ApplicationErrorCode.Value);

        var quicStreamContext = Assert.IsType <QuicStreamContext>(serverStream);

        Assert.Equal((long)Http3ErrorCode.InternalError, quicStreamContext.Error);

        // Both send and receive loops have exited.
        await quicStreamContext._processingTask.DefaultTimeout();

        await closedTcs.Task.DefaultTimeout();
    }
Ejemplo n.º 2
0
    public async Task AcceptAsync_ServerStartsAndStopsUnidirectionStream_ClientAccepts()
    {
        // Arrange
        await using var connectionListener = await QuicTestHelpers.CreateConnectionListenerFactory(LoggerFactory);

        var options = QuicTestHelpers.CreateClientConnectionOptions(connectionListener.EndPoint);

        await using var quicConnection = await QuicConnection.ConnectAsync(options);

        var serverConnection = await connectionListener.AcceptAndAddFeatureAsync().DefaultTimeout();

        // Act
        var acceptTask = quicConnection.AcceptInboundStreamAsync();

        await using var serverStream = await serverConnection.ConnectAsync();

        await serverStream.Transport.Output.WriteAsync(TestData).DefaultTimeout();

        await using var clientStream = await acceptTask.DefaultTimeout();

        // Assert
        Assert.NotNull(clientStream);

        // Read data from server.
        var data      = new List <byte>();
        var buffer    = new byte[1024];
        var readCount = 0;

        while ((readCount = await clientStream.ReadAsync(buffer).DefaultTimeout()) != -1)
        {
            data.AddRange(buffer.AsMemory(0, readCount).ToArray());
            if (data.Count == TestData.Length)
            {
                break;
            }
        }
        Assert.Equal(TestData, data);

        // Complete server.
        await serverStream.Transport.Output.CompleteAsync().DefaultTimeout();

        // Receive complete in client.
        readCount = await clientStream.ReadAsync(buffer).DefaultTimeout();

        Assert.Equal(0, readCount);
    }
    public async Task ServerToClientUnidirectionalStream_ServerAborts_ClientGetsAbort()
    {
        // Arrange
        await using var connectionListener = await QuicTestHelpers.CreateConnectionListenerFactory(LoggerFactory);

        var options = QuicTestHelpers.CreateClientConnectionOptions(connectionListener.EndPoint);

        using var quicConnection = new QuicConnection(QuicImplementationProviders.MsQuic, options);
        await quicConnection.ConnectAsync().DefaultTimeout();

        await using var serverConnection = await connectionListener.AcceptAndAddFeatureAsync().DefaultTimeout();

        // Act
        var features = new FeatureCollection();

        features.Set <IStreamDirectionFeature>(new DefaultStreamDirectionFeature(canRead: false, canWrite: true));
        var serverStream = await serverConnection.ConnectAsync(features).DefaultTimeout();

        await serverStream.Transport.Output.WriteAsync(TestData).DefaultTimeout();

        await using var clientStream = await quicConnection.AcceptStreamAsync();

        var data = await clientStream.ReadAtLeastLengthAsync(TestData.Length).DefaultTimeout();

        Assert.Equal(TestData, data);

        Logger.LogInformation("Server aborting stream");
        ((IProtocolErrorCodeFeature)serverStream).Error = (long)Http3ErrorCode.InternalError;
        serverStream.Abort(new ConnectionAbortedException("Test message"));

        var ex = await Assert.ThrowsAsync <QuicStreamAbortedException>(() => clientStream.ReadAsync(new byte[1024]).AsTask()).DefaultTimeout();

        // Assert
        Assert.Equal((long)Http3ErrorCode.InternalError, ex.ErrorCode);

        var quicStreamContext = Assert.IsType <QuicStreamContext>(serverStream);

        Assert.True(quicStreamContext.CanWrite);
        Assert.False(quicStreamContext.CanRead);

        // Both send and receive loops have exited.
        await quicStreamContext._processingTask.DefaultTimeout();

        Assert.Contains(TestSink.Writes, m => m.Message.Contains(@"shutting down writes because: ""Test message""."));
    }
Ejemplo n.º 4
0
    public async Task AcceptAsync_ClientStartsAndStopsUnidirectionStream_ServerAccepts()
    {
        // Arrange
        await using var connectionListener = await QuicTestHelpers.CreateConnectionListenerFactory(LoggerFactory);

        var options = QuicTestHelpers.CreateClientConnectionOptions(connectionListener.EndPoint);

        using var quicConnection = new QuicConnection(QuicImplementationProviders.MsQuic, options);
        await quicConnection.ConnectAsync().DefaultTimeout();

        await using var serverConnection = await connectionListener.AcceptAndAddFeatureAsync().DefaultTimeout();

        // Act
        var acceptTask = serverConnection.AcceptAsync();

        await using var clientStream = await quicConnection.OpenUnidirectionalStreamAsync();

        await clientStream.WriteAsync(TestData);

        await using var serverStream = await acceptTask.DefaultTimeout();

        // Assert
        Assert.NotNull(serverStream);
        Assert.False(serverStream.ConnectionClosed.IsCancellationRequested);

        var closedTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);

        serverStream.ConnectionClosed.Register(() => closedTcs.SetResult());

        // Read data from client.
        var read = await serverStream.Transport.Input.ReadAtLeastAsync(TestData.Length).DefaultTimeout();

        Assert.Equal(TestData, read.Buffer.ToArray());
        serverStream.Transport.Input.AdvanceTo(read.Buffer.End);

        // Shutdown client.
        clientStream.Shutdown();

        // Receive shutdown on server.
        read = await serverStream.Transport.Input.ReadAsync().DefaultTimeout();

        Assert.True(read.IsCompleted);

        await closedTcs.Task.DefaultTimeout();
    }
Ejemplo n.º 5
0
    public async Task AcceptAsync_CancellationThenAccept_AcceptStreamAfterCancellation()
    {
        // Arrange
        var connectionClosedTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);

        await using var connectionListener = await QuicTestHelpers.CreateConnectionListenerFactory(LoggerFactory);

        // Act
        var acceptTask = connectionListener.AcceptAndAddFeatureAsync().DefaultTimeout();

        var options = QuicTestHelpers.CreateClientConnectionOptions(connectionListener.EndPoint);

        using var clientConnection = new QuicConnection(QuicImplementationProviders.MsQuic, options);
        await clientConnection.ConnectAsync().DefaultTimeout();

        await using var serverConnection = await acceptTask.DefaultTimeout();

        // Wait for stream and then cancel
        var cts = new CancellationTokenSource();
        var acceptStreamTask = serverConnection.AcceptAsync(cts.Token);

        cts.Cancel();

        var serverStream = await acceptStreamTask.DefaultTimeout();

        Assert.Null(serverStream);

        // Wait for stream after cancellation
        acceptStreamTask = serverConnection.AcceptAsync();

        await using var clientStream = await clientConnection.OpenBidirectionalStreamAsync();

        await clientStream.WriteAsync(TestData);

        // Assert
        serverStream = await acceptStreamTask.DefaultTimeout();

        Assert.NotNull(serverStream);

        var read = await serverStream.Transport.Input.ReadAtLeastAsync(TestData.Length).DefaultTimeout();

        Assert.Equal(TestData, read.Buffer.ToArray());
        serverStream.Transport.Input.AdvanceTo(read.Buffer.End);
    }
    public async Task ServerToClientUnidirectionalStream_ServerWritesDataAndCompletes_GracefullyClosed()
    {
        // Arrange
        await using var connectionListener = await QuicTestHelpers.CreateConnectionListenerFactory(LoggerFactory);

        var options = QuicTestHelpers.CreateClientConnectionOptions(connectionListener.EndPoint);

        using var quicConnection = new QuicConnection(QuicImplementationProviders.MsQuic, options);
        await quicConnection.ConnectAsync().DefaultTimeout();

        await using var serverConnection = await connectionListener.AcceptAndAddFeatureAsync().DefaultTimeout();

        // Act
        var features = new FeatureCollection();

        features.Set <IStreamDirectionFeature>(new DefaultStreamDirectionFeature(canRead: false, canWrite: true));
        var serverStream = await serverConnection.ConnectAsync(features).DefaultTimeout();

        await serverStream.Transport.Output.WriteAsync(TestData).DefaultTimeout();

        await using var clientStream = await quicConnection.AcceptStreamAsync();

        var data = await clientStream.ReadAtLeastLengthAsync(TestData.Length).DefaultTimeout();

        Assert.Equal(TestData, data);

        await serverStream.Transport.Output.CompleteAsync();

        var readCount = await clientStream.ReadAsync(new byte[1024]).DefaultTimeout();

        // Assert
        Assert.Equal(0, readCount);

        var quicStreamContext = Assert.IsType <QuicStreamContext>(serverStream);

        Assert.True(quicStreamContext.CanWrite);
        Assert.False(quicStreamContext.CanRead);

        // Both send and receive loops have exited.
        await quicStreamContext._processingTask.DefaultTimeout();

        Assert.Contains(TestSink.Writes, m => m.Message.Contains(@"shutting down writes because: ""The QUIC transport's send loop completed gracefully.""."));
    }
Ejemplo n.º 7
0
    public async Task StreamPool_ManyConcurrentStreams_StreamPoolFull()
    {
        // Arrange
        await using var connectionListener = await QuicTestHelpers.CreateConnectionListenerFactory(LoggerFactory);

        var options = QuicTestHelpers.CreateClientConnectionOptions(connectionListener.EndPoint);

        using var clientConnection = new QuicConnection(QuicImplementationProviders.MsQuic, options);
        await clientConnection.ConnectAsync().DefaultTimeout();

        await using var serverConnection = await connectionListener.AcceptAndAddFeatureAsync().DefaultTimeout();

        var testHeartbeatFeature = new TestHeartbeatFeature();

        serverConnection.Features.Set <IConnectionHeartbeatFeature>(testHeartbeatFeature);

        // Act
        var quicConnectionContext = Assert.IsType <QuicConnectionContext>(serverConnection);

        Assert.Equal(0, quicConnectionContext.StreamPool.Count);

        var pauseCompleteTcs          = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
        var allConnectionsOnServerTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
        var streamTasks  = new List <Task>();
        var requestState = new RequestState(clientConnection, serverConnection, allConnectionsOnServerTcs, pauseCompleteTcs.Task);

        const int StreamsSent = 101;

        for (var i = 0; i < StreamsSent; i++)
        {
            streamTasks.Add(SendStream(requestState));
        }

        await allConnectionsOnServerTcs.Task.DefaultTimeout();

        pauseCompleteTcs.SetResult();

        await Task.WhenAll(streamTasks).DefaultTimeout();

        // Assert
        // Up to 100 streams are pooled.
        Assert.Equal(100, quicConnectionContext.StreamPool.Count);
Ejemplo n.º 8
0
    public async Task AcceptAsync_ClientCreatesConnection_ServerAccepts()
    {
        // Arrange
        await using var connectionListener = await QuicTestHelpers.CreateConnectionListenerFactory(LoggerFactory);

        // Act
        var acceptTask = connectionListener.AcceptAndAddFeatureAsync().DefaultTimeout();

        var options = QuicTestHelpers.CreateClientConnectionOptions(connectionListener.EndPoint);

        await using var clientConnection = await QuicConnection.ConnectAsync(options);

        // Assert
        await using var serverConnection = await acceptTask.DefaultTimeout();

        Assert.False(serverConnection.ConnectionClosed.IsCancellationRequested);

        await serverConnection.DisposeAsync().AsTask().DefaultTimeout();

        // ConnectionClosed isn't triggered because the server initiated close.
        Assert.False(serverConnection.ConnectionClosed.IsCancellationRequested);
    }
Ejemplo n.º 9
0
    public async Task BidirectionalStream_ServerReadsDataAndCompletes_GracefullyClosed()
    {
        // Arrange
        await using var connectionListener = await QuicTestHelpers.CreateConnectionListenerFactory(LoggerFactory);

        var options = QuicTestHelpers.CreateClientConnectionOptions(connectionListener.EndPoint);

        await using var clientConnection = await QuicConnection.ConnectAsync(options);

        await using var serverConnection = await connectionListener.AcceptAndAddFeatureAsync().DefaultTimeout();

        // Act
        await QuicTestHelpers.CreateAndCompleteBidirectionalStreamGracefully(clientConnection, serverConnection, Logger);

        Assert.Contains(LogMessages, m => m.Message.Contains("send loop completed gracefully"));

        var quicConnectionContext = Assert.IsType <QuicConnectionContext>(serverConnection);

        Assert.Equal(1, quicConnectionContext.StreamPool.Count);

        Assert.Contains(TestSink.Writes, m => m.Message.Contains(@"shutting down writes because: ""The QUIC transport's send loop completed gracefully.""."));
    }
Ejemplo n.º 10
0
    public async Task BidirectionalStream_MultipleStreamsOnConnection_ReusedFromPool()
    {
        // Arrange
        await using var connectionListener = await QuicTestHelpers.CreateConnectionListenerFactory(LoggerFactory);

        var options = QuicTestHelpers.CreateClientConnectionOptions(connectionListener.EndPoint);

        await using var clientConnection = await QuicConnection.ConnectAsync(options);

        await using var serverConnection = await connectionListener.AcceptAndAddFeatureAsync().DefaultTimeout();

        // Act
        var stream1 = await QuicTestHelpers.CreateAndCompleteBidirectionalStreamGracefully(clientConnection, serverConnection, Logger);

        var stream2 = await QuicTestHelpers.CreateAndCompleteBidirectionalStreamGracefully(clientConnection, serverConnection, Logger);

        Assert.Same(stream1, stream2);

        var quicConnectionContext = Assert.IsType <QuicConnectionContext>(serverConnection);

        Assert.Equal(1, quicConnectionContext.StreamPool.Count);
    }
Ejemplo n.º 11
0
    public async Task ClientToServerUnidirectionalStream_ServerReadsData_GracefullyClosed()
    {
        // Arrange
        await using var connectionListener = await QuicTestHelpers.CreateConnectionListenerFactory(LoggerFactory);

        var options = QuicTestHelpers.CreateClientConnectionOptions(connectionListener.EndPoint);

        using var quicConnection = new QuicConnection(QuicImplementationProviders.MsQuic, options);
        await quicConnection.ConnectAsync().DefaultTimeout();

        await using var serverConnection = await connectionListener.AcceptAndAddFeatureAsync().DefaultTimeout();

        // Act
        await using var clientStream = await quicConnection.OpenUnidirectionalStreamAsync();

        await clientStream.WriteAsync(TestData, endStream : true).DefaultTimeout();

        await using var serverStream = await serverConnection.AcceptAsync().DefaultTimeout();

        var readResult = await serverStream.Transport.Input.ReadAtLeastAsync(TestData.Length).DefaultTimeout();

        serverStream.Transport.Input.AdvanceTo(readResult.Buffer.End);

        // Input should be completed.
        readResult = await serverStream.Transport.Input.ReadAsync().DefaultTimeout();

        // Assert
        Assert.True(readResult.IsCompleted);

        var quicStreamContext = Assert.IsType <QuicStreamContext>(serverStream);

        Assert.False(quicStreamContext.CanWrite);
        Assert.True(quicStreamContext.CanRead);

        // Both send and receive loops have exited.
        await quicStreamContext._processingTask.DefaultTimeout();
    }
Ejemplo n.º 12
0
    public async Task StreamPool_Heartbeat_ExpiredStreamRemoved()
    {
        // Arrange
        var now             = new DateTimeOffset(2021, 7, 6, 12, 0, 0, TimeSpan.Zero);
        var testSystemClock = new TestSystemClock {
            UtcNow = now
        };

        await using var connectionListener = await QuicTestHelpers.CreateConnectionListenerFactory(LoggerFactory, testSystemClock);

        var options = QuicTestHelpers.CreateClientConnectionOptions(connectionListener.EndPoint);

        using var clientConnection = new QuicConnection(QuicImplementationProviders.MsQuic, options);
        await clientConnection.ConnectAsync().DefaultTimeout();

        await using var serverConnection = await connectionListener.AcceptAndAddFeatureAsync().DefaultTimeout();

        var testHeartbeatFeature = new TestHeartbeatFeature();

        serverConnection.Features.Set <IConnectionHeartbeatFeature>(testHeartbeatFeature);

        // Act & Assert
        var quicConnectionContext = Assert.IsType <QuicConnectionContext>(serverConnection);

        Assert.Equal(0, quicConnectionContext.StreamPool.Count);

        var stream1 = await QuicTestHelpers.CreateAndCompleteBidirectionalStreamGracefully(clientConnection, serverConnection);

        Assert.Equal(1, quicConnectionContext.StreamPool.Count);
        QuicStreamContext pooledStream = quicConnectionContext.StreamPool._array[0];

        Assert.Same(stream1, pooledStream);
        Assert.Equal(now.Ticks + QuicConnectionContext.StreamPoolExpiryTicks, pooledStream.PoolExpirationTicks);

        now = now.AddMilliseconds(100);
        testSystemClock.UtcNow = now;
        testHeartbeatFeature.RaiseHeartbeat();
        // Not removed.
        Assert.Equal(1, quicConnectionContext.StreamPool.Count);

        var stream2 = await QuicTestHelpers.CreateAndCompleteBidirectionalStreamGracefully(clientConnection, serverConnection);

        Assert.Equal(1, quicConnectionContext.StreamPool.Count);
        pooledStream = quicConnectionContext.StreamPool._array[0];
        Assert.Same(stream1, pooledStream);
        Assert.Equal(now.Ticks + QuicConnectionContext.StreamPoolExpiryTicks, pooledStream.PoolExpirationTicks);

        Assert.Same(stream1, stream2);

        now = now.AddTicks(QuicConnectionContext.StreamPoolExpiryTicks);
        testSystemClock.UtcNow = now;
        testHeartbeatFeature.RaiseHeartbeat();
        // Not removed.
        Assert.Equal(1, quicConnectionContext.StreamPool.Count);

        now = now.AddTicks(1);
        testSystemClock.UtcNow = now;
        testHeartbeatFeature.RaiseHeartbeat();
        // Removed.
        Assert.Equal(0, quicConnectionContext.StreamPool.Count);
    }
Ejemplo n.º 13
0
    public async Task BidirectionalStream_ServerWritesDataAndDisposes_ClientReadsData(int dataLength)
    {
        // Arrange
        var testData = new byte[dataLength];

        for (int i = 0; i < dataLength; i++)
        {
            testData[i] = (byte)i;
        }

        await using var connectionListener = await QuicTestHelpers.CreateConnectionListenerFactory(LoggerFactory);

        var options = QuicTestHelpers.CreateClientConnectionOptions(connectionListener.EndPoint);

        using var clientConnection = new QuicConnection(QuicImplementationProviders.MsQuic, options);
        await clientConnection.ConnectAsync().DefaultTimeout();

        await using var serverConnection = await connectionListener.AcceptAndAddFeatureAsync().DefaultTimeout();

        // Act
        Logger.LogInformation("Client starting stream.");
        var clientStream = await clientConnection.OpenBidirectionalStreamAsync();

        await clientStream.WriteAsync(TestData, endStream : true).DefaultTimeout();

        var serverStream = await serverConnection.AcceptAsync().DefaultTimeout();

        Logger.LogInformation("Server accepted stream.");
        var readResult = await serverStream.Transport.Input.ReadAtLeastAsync(TestData.Length).DefaultTimeout();

        serverStream.Transport.Input.AdvanceTo(readResult.Buffer.End);

        // Input should be completed.
        readResult = await serverStream.Transport.Input.ReadAsync().DefaultTimeout();

        Assert.True(readResult.IsCompleted);

        Logger.LogInformation("Server sending data.");
        await serverStream.Transport.Output.WriteAsync(testData).DefaultTimeout();

        Logger.LogInformation("Server completing pipes.");
        await serverStream.Transport.Input.CompleteAsync().DefaultTimeout();

        await serverStream.Transport.Output.CompleteAsync().DefaultTimeout();

        Logger.LogInformation("Client reading until end of stream.");
        var data = await clientStream.ReadUntilEndAsync().DefaultTimeout();

        Assert.Equal(testData.Length, data.Length);
        Assert.Equal(testData, data);

        var quicStreamContext = Assert.IsType <QuicStreamContext>(serverStream);

        Logger.LogInformation("Server waiting for send and receiving loops to complete.");
        await quicStreamContext._processingTask.DefaultTimeout();

        Assert.True(quicStreamContext.CanWrite);
        Assert.True(quicStreamContext.CanRead);

        Logger.LogInformation("Server disposing stream.");
        await quicStreamContext.DisposeAsync().DefaultTimeout();

        quicStreamContext.Dispose();

        var quicConnectionContext = Assert.IsType <QuicConnectionContext>(serverConnection);

        Assert.Equal(1, quicConnectionContext.StreamPool.Count);
    }
Ejemplo n.º 14
0
    public async Task StreamPool_StreamAbortedOnClientAndServer_NotPooled()
    {
        // Arrange
        await using var connectionListener = await QuicTestHelpers.CreateConnectionListenerFactory(LoggerFactory);

        var options = QuicTestHelpers.CreateClientConnectionOptions(connectionListener.EndPoint);

        await using var clientConnection = await QuicConnection.ConnectAsync(options);

        await using var serverConnection = await connectionListener.AcceptAndAddFeatureAsync().DefaultTimeout();

        var testHeartbeatFeature = new TestHeartbeatFeature();

        serverConnection.Features.Set <IConnectionHeartbeatFeature>(testHeartbeatFeature);

        // Act & Assert
        var quicConnectionContext = Assert.IsType <QuicConnectionContext>(serverConnection);

        Assert.Equal(0, quicConnectionContext.StreamPool.Count);

        var clientStream = await clientConnection.OpenOutboundStreamAsync(QuicStreamType.Bidirectional);

        await clientStream.WriteAsync(TestData).DefaultTimeout();

        var serverStream = await serverConnection.AcceptAsync().DefaultTimeout();

        var readResult = await serverStream.Transport.Input.ReadAtLeastAsync(TestData.Length).DefaultTimeout();

        serverStream.Transport.Input.AdvanceTo(readResult.Buffer.End);

        clientStream.Abort(QuicAbortDirection.Write, (long)Http3ErrorCode.InternalError);

        // Receive abort form client.
        var serverEx = await Assert.ThrowsAsync <ConnectionResetException>(() => serverStream.Transport.Input.ReadAsync().AsTask()).DefaultTimeout();

        Assert.Equal("Stream aborted by peer (258).", serverEx.Message);
        Assert.Equal((long)Http3ErrorCode.InternalError, ((QuicException)serverEx.InnerException).ApplicationErrorCode.Value);

        serverStream.Features.Get <IProtocolErrorCodeFeature>().Error = (long)Http3ErrorCode.RequestRejected;
        serverStream.Abort(new ConnectionAbortedException("Test message."));

        // Complete server.
        await serverStream.Transport.Input.CompleteAsync();

        await serverStream.Transport.Output.CompleteAsync();

        var buffer   = new byte[1024];
        var clientEx = await Assert.ThrowsAsync <QuicException>(() => clientStream.ReadAsync(buffer).AsTask()).DefaultTimeout();

        Assert.Equal(QuicError.StreamAborted, clientEx.QuicError);
        Assert.Equal((long)Http3ErrorCode.RequestRejected, clientEx.ApplicationErrorCode.Value);

        var quicStreamContext = Assert.IsType <QuicStreamContext>(serverStream);

        // Both send and receive loops have exited.
        await quicStreamContext._processingTask.DefaultTimeout();

        await quicStreamContext.DisposeAsync();

        Assert.Equal(0, quicConnectionContext.StreamPool.Count);
    }
Ejemplo n.º 15
0
    public async Task BidirectionalStream_ClientAbortedAfterDisposeCalled_NotPooled()
    {
        // Arrange
        using var httpEventSource = new HttpEventSourceListener(LoggerFactory);

        await using var connectionListener = await QuicTestHelpers.CreateConnectionListenerFactory(LoggerFactory);

        var options = QuicTestHelpers.CreateClientConnectionOptions(connectionListener.EndPoint);

        await using var clientConnection = await QuicConnection.ConnectAsync(options);

        await using var serverConnection = await connectionListener.AcceptAndAddFeatureAsync().DefaultTimeout();

        // Act
        Logger.LogInformation("Client starting stream.");
        var clientStream = await clientConnection.OpenOutboundStreamAsync(QuicStreamType.Bidirectional);

        await clientStream.WriteAsync(TestData).DefaultTimeout();

        var readTask = clientStream.ReadUntilEndAsync();

        Logger.LogInformation("Server accepted stream.");
        var serverStream = await serverConnection.AcceptAsync().DefaultTimeout();

        var readResult = await serverStream.Transport.Input.ReadAtLeastAsync(TestData.Length).DefaultTimeout();

        serverStream.Transport.Input.AdvanceTo(readResult.Buffer.End);

        // Server sends a large response that will make it wait to complete sends.
        Logger.LogInformation("Server writing a large response.");
        await serverStream.Transport.Output.WriteAsync(new byte[1024 * 1024 * 32]).DefaultTimeout();

        // Complete reading and writing.
        Logger.LogInformation("Server complete reading and writing.");
        await serverStream.Transport.Input.CompleteAsync();

        await serverStream.Transport.Output.CompleteAsync();

        Logger.LogInformation("Client wait to finish reading.");
        await readTask.DefaultTimeout();

        var quicStreamContext = Assert.IsType <QuicStreamContext>(serverStream);

        // Server starts disposing
        Logger.LogInformation("Server starts disposing.");
        var disposeTask = quicStreamContext.DisposeAsync();

        // Client aborts while server is draining
        clientStream.Abort(QuicAbortDirection.Read, (long)Http3ErrorCode.RequestCancelled);
        clientStream.Abort(QuicAbortDirection.Write, (long)Http3ErrorCode.RequestCancelled);

        // Server finishes disposing
        Logger.LogInformation("Wait for server finish disposing.");
        await disposeTask.DefaultTimeout();

        quicStreamContext.Dispose();

        var quicConnectionContext = Assert.IsType <QuicConnectionContext>(serverConnection);

        // Assert
        Assert.Equal(0, quicConnectionContext.StreamPool.Count);
    }