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();
    }
    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();
    }
    internal async Task WebTransportStream_StreamTypesAreDefinedCorrectly(WebTransportStreamType type, bool canRead, bool canWrite)
    {
        var memory = new Memory <byte>(new byte[5]);
        var stream = WebTransportTestUtilities.CreateStream(type, memory);

        var streamDirectionFeature = stream.Features.GetRequiredFeature <IStreamDirectionFeature>();

        Assert.Equal(canRead, streamDirectionFeature.CanRead);
        Assert.Equal(canWrite, streamDirectionFeature.CanWrite);

        await stream.DisposeAsync();

        // test that you can't write or read from a stream after disposing
        Assert.False(streamDirectionFeature.CanRead);
        Assert.False(streamDirectionFeature.CanWrite);
    }
    internal async Task WebTransportStream_WritingFlushingReadingWorks()
    {
        var memory = new Memory <byte>(new byte[5]);

        var stream = WebTransportTestUtilities.CreateStream(WebTransportStreamType.Bidirectional, memory);

        var input = new ReadOnlyMemory <byte>(RandomBytes);
        await stream.Transport.Output.WriteAsync(input, CancellationToken.None);

        await stream.Transport.Output.FlushAsync();

        var memoryOut = new Memory <byte>(new byte[5]);
        var length    = await stream.Transport.Input.AsStream().ReadAsync(memoryOut, CancellationToken.None);

        Assert.Equal(5, length);
        Assert.Equal(input.ToArray(), memoryOut.ToArray());
    }
    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();
    }