File: Http3\WebTransport\WebTransportSessionTests.cs
Web Access
Project: src\src\Servers\Kestrel\test\InMemory.FunctionalTests\InMemory.FunctionalTests.csproj (InMemory.FunctionalTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using Microsoft.AspNetCore.Connections.Features;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.Kestrel.Core.WebTransport;
 
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests;
 
public class WebTransportSessionTests : Http3TestBase
{
    [Fact]
    public async Task WebTransportSession_CanOpenNewStream()
    {
        Http3Api._serviceContext.ServerOptions.EnableWebTransportAndH3Datagrams = true;
 
        var exitTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
 
        var session = await WebTransportTestUtilities.GenerateSession(Http3Api, exitTcs);
 
        var stream = await session.OpenUnidirectionalStreamAsync(CancellationToken.None);
 
        //verify that we opened an output stream
        Assert.NotNull(stream);
        var streamDirectionFeature = stream.Features.GetRequiredFeature<IStreamDirectionFeature>();
        Assert.True(streamDirectionFeature.CanWrite);
        Assert.False(streamDirectionFeature.CanRead);
 
        // end the application
        exitTcs.SetResult();
    }
 
    [Fact]
    public async Task WebTransportSession_AcceptNewStreamsInOrderOfArrival()
    {
        Http3Api._serviceContext.ServerOptions.EnableWebTransportAndH3Datagrams = true; // TODO add more sync code as now it is flaky
 
        var exitTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
        var session = await WebTransportTestUtilities.GenerateSession(Http3Api, exitTcs);
 
        // pretend that we received 2 new stream requests from a client
        session.AddStream(WebTransportTestUtilities.CreateStream(WebTransportStreamType.Bidirectional));
        session.AddStream(WebTransportTestUtilities.CreateStream(WebTransportStreamType.Input));
 
        var stream = await session.AcceptStreamAsync(CancellationToken.None);
 
        // verify that we accepted a bidirectional stream
        Assert.NotNull(stream);
        var streamDirectionFeature = stream.Features.GetRequiredFeature<IStreamDirectionFeature>();
        Assert.True(streamDirectionFeature.CanWrite);
        Assert.True(streamDirectionFeature.CanRead);
 
        var stream2 = await session.AcceptStreamAsync(CancellationToken.None);
 
        // verify that we accepted a unidirectional stream
        Assert.NotNull(stream2);
        var streamDirectionFeature2 = stream2.Features.GetRequiredFeature<IStreamDirectionFeature>();
        Assert.False(streamDirectionFeature2.CanWrite);
        Assert.True(streamDirectionFeature2.CanRead);
 
        exitTcs.SetResult();
    }
 
    [Theory]
    [InlineData(0)]
    [InlineData(1)]
    [InlineData(2)]
    [InlineData(3)]
    public async Task WebTransportSession_ClosesProperly(int method)
    {
        Http3Api._serviceContext.ServerOptions.EnableWebTransportAndH3Datagrams = true;
 
        var exitTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
        var session = await WebTransportTestUtilities.GenerateSession(Http3Api, exitTcs);
 
        switch (method)
        {
            case 0: // manual abort
                session.Abort(new(), System.Net.Http.Http3ErrorCode.InternalError);
                break;
            case 1: // manual graceful close
                session.OnClientConnectionClosed();
                break;
            case 2: // automatic graceful close due to application and connection ending
                exitTcs.SetResult();
                break;
            case 3: // automatic abort due to host stream aborting
                Http3Api.Connection._streams[session.SessionId].Abort(new(), System.Net.Http.Http3ErrorCode.InternalError);
                break;
        }
 
        // check that all future method calls which are not related to closing throw
        Assert.Null(await session.AcceptStreamAsync(CancellationToken.None));
        Assert.Null(await session.OpenUnidirectionalStreamAsync(CancellationToken.None));
 
        // doublec check that no exceptions are thrown
        var _ = WebTransportTestUtilities.CreateStream(WebTransportStreamType.Bidirectional);
 
        exitTcs.TrySetResult();
    }
}