<TargetFrameworks>$(NetCoreAppCurrent)</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
- <Compile Include="System\IO\*" />
+ <Compile Include="System\IO\*.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="$(CommonTestPath)System\IO\ConnectedStreams.cs" Link="System\IO\ConnectedStreams.cs" />
#region WaitAsync polyfills
// Test polyfills when targeting a platform that doesn't have these ConfigureAwait overloads on Task
+ public static Task WaitAsync(this Task task, int millisecondsTimeout) =>
+ WaitAsync(task, TimeSpan.FromMilliseconds(millisecondsTimeout), default);
+
public static Task WaitAsync(this Task task, TimeSpan timeout) =>
WaitAsync(task, timeout, default);
}
}
+ public static Task<TResult> WaitAsync<TResult>(this Task<TResult> task, int millisecondsTimeout) =>
+ WaitAsync(task, TimeSpan.FromMilliseconds(millisecondsTimeout), default);
+
public static Task<TResult> WaitAsync<TResult>(this Task<TResult> task, TimeSpan timeout) =>
WaitAsync(task, timeout, default);
public static async Task WhenAllOrAnyFailed(this Task[] tasks, int millisecondsTimeout) =>
await tasks.WhenAllOrAnyFailed().WaitAsync(TimeSpan.FromMilliseconds(millisecondsTimeout));
+ public static async Task WhenAllOrAnyFailed(Task t1, Task t2, int millisecondsTimeout) =>
+ await new Task[] {t1, t2}.WhenAllOrAnyFailed(millisecondsTimeout);
+
public static async Task WhenAllOrAnyFailed(this Task[] tasks)
{
try
[ConditionalClass(typeof(QuicTestBase<MsQuicProviderFactory>), nameof(IsSupported))]
public class MsQuicTests : QuicTestBase<MsQuicProviderFactory>
{
- readonly ITestOutputHelper _output;
private static ReadOnlyMemory<byte> s_data = Encoding.UTF8.GetBytes("Hello world!");
- public MsQuicTests(ITestOutputHelper output)
- {
- _output = output;
- }
+ public MsQuicTests(ITestOutputHelper output) : base(output) { }
[Fact]
public async Task UnidirectionalAndBidirectionalStreamCountsWork()
{
using QuicListener listener = CreateQuicListener();
using QuicConnection clientConnection = CreateQuicConnection(listener.ListenEndPoint);
+ Task<QuicConnection> serverTask = listener.AcceptConnectionAsync().AsTask();
+ await TaskTimeoutExtensions.WhenAllOrAnyFailed(clientConnection.ConnectAsync().AsTask(), serverTask, PassingTestTimeoutMilliseconds);
+ using QuicConnection serverConnection = serverTask.Result;
- ValueTask clientTask = clientConnection.ConnectAsync();
- using QuicConnection serverConnection = await listener.AcceptConnectionAsync();
- await clientTask;
Assert.Equal(100, serverConnection.GetRemoteAvailableBidirectionalStreamCount());
Assert.Equal(100, serverConnection.GetRemoteAvailableUnidirectionalStreamCount());
}
};
using QuicConnection clientConnection = new QuicConnection(QuicImplementationProviders.MsQuic, options);
+ Task<QuicConnection> serverTask = listener.AcceptConnectionAsync().AsTask();
+ await TaskTimeoutExtensions.WhenAllOrAnyFailed(clientConnection.ConnectAsync().AsTask(), serverTask, PassingTestTimeoutMilliseconds);
+ using QuicConnection serverConnection = serverTask.Result;
- ValueTask clientTask = clientConnection.ConnectAsync();
- using QuicConnection serverConnection = await listener.AcceptConnectionAsync();
- await clientTask;
Assert.Equal(100, clientConnection.GetRemoteAvailableBidirectionalStreamCount());
Assert.Equal(100, clientConnection.GetRemoteAvailableUnidirectionalStreamCount());
Assert.Equal(10, serverConnection.GetRemoteAvailableBidirectionalStreamCount());
};
using QuicConnection clientConnection = new QuicConnection(QuicImplementationProviders.MsQuic, options);
- ValueTask clientTask = clientConnection.ConnectAsync();
-
- using QuicConnection serverConnection = await listener.AcceptConnectionAsync();
- await clientTask;
+ Task<QuicConnection> serverTask = listener.AcceptConnectionAsync().AsTask();
+ await TaskTimeoutExtensions.WhenAllOrAnyFailed(clientConnection.ConnectAsync().AsTask(), serverTask, PassingTestTimeoutMilliseconds);
+ using QuicConnection serverConnection = serverTask.Result;
}
[Fact]
clientOptions.ClientAuthenticationOptions.ClientCertificates = new X509CertificateCollection() { ClientCertificate };
using QuicConnection clientConnection = new QuicConnection(QuicImplementationProviders.MsQuic, clientOptions);
- ValueTask clientTask = clientConnection.ConnectAsync();
+ Task<QuicConnection> serverTask = listener.AcceptConnectionAsync().AsTask();
+ await TaskTimeoutExtensions.WhenAllOrAnyFailed(clientConnection.ConnectAsync().AsTask(), serverTask, PassingTestTimeoutMilliseconds);
+ using QuicConnection serverConnection = serverTask.Result;
- using QuicConnection serverConnection = await listener.AcceptConnectionAsync();
- await clientTask;
// Verify functionality of the connections.
await PingPong(clientConnection, serverConnection);
// check we completed the client certificate verification.
{
using QuicListener listener = CreateQuicListener(maxUnidirectionalStreams: 1);
using QuicConnection clientConnection = CreateQuicConnection(listener.ListenEndPoint);
-
- ValueTask clientTask = clientConnection.ConnectAsync();
- using QuicConnection serverConnection = await listener.AcceptConnectionAsync();
- await clientTask;
+ Task<QuicConnection> serverTask = listener.AcceptConnectionAsync().AsTask();
+ await TaskTimeoutExtensions.WhenAllOrAnyFailed(clientConnection.ConnectAsync().AsTask(), serverTask, PassingTestTimeoutMilliseconds);
+ using QuicConnection serverConnection = serverTask.Result;
listener.Dispose();
// No stream opened yet, should return immediately.
using QuicListener listener = CreateQuicListener(maxBidirectionalStreams: 1);
using QuicConnection clientConnection = CreateQuicConnection(listener.ListenEndPoint);
- ValueTask clientTask = clientConnection.ConnectAsync();
- using QuicConnection serverConnection = await listener.AcceptConnectionAsync();
- await clientTask;
+ Task<QuicConnection> serverTask = listener.AcceptConnectionAsync().AsTask();
+ await TaskTimeoutExtensions.WhenAllOrAnyFailed(clientConnection.ConnectAsync().AsTask(), serverTask, PassingTestTimeoutMilliseconds);
+ using QuicConnection serverConnection = serverTask.Result;
// No stream opened yet, should return immediately.
Assert.True(clientConnection.WaitForAvailableBidirectionalStreamsAsync().IsCompletedSuccessfully);
};
using QuicConnection clientConnection = new QuicConnection(QuicImplementationProviders.MsQuic, options);
- ValueTask clientTask = clientConnection.ConnectAsync();
- using QuicConnection serverConnection = await listener.AcceptConnectionAsync();
- await clientTask;
+ Task<QuicConnection> serverTask = listener.AcceptConnectionAsync().AsTask();
+ await TaskTimeoutExtensions.WhenAllOrAnyFailed(clientConnection.ConnectAsync().AsTask(), serverTask, PassingTestTimeoutMilliseconds);
+ using QuicConnection serverConnection = serverTask.Result;
await Assert.ThrowsAsync<QuicOperationAbortedException>(async () => await serverConnection.AcceptStreamAsync().AsTask().WaitAsync(TimeSpan.FromSeconds(100)));
}
[Theory]
[MemberData(nameof(WriteData))]
- [ActiveIssue("https://github.com/dotnet/runtime/issues/49157")]
public async Task WriteTests(int[][] writes, WriteType writeType)
{
await RunClientServer(
using QuicListener listener = CreateQuicListener();
using QuicConnection clientConnection = CreateQuicConnection(listener.ListenEndPoint);
- ValueTask clientTask = clientConnection.ConnectAsync();
- using QuicConnection serverConnection = await listener.AcceptConnectionAsync();
- await clientTask;
+ Task<QuicConnection> serverTask = listener.AcceptConnectionAsync().AsTask();
+ await TaskTimeoutExtensions.WhenAllOrAnyFailed(clientConnection.ConnectAsync().AsTask(), serverTask, PassingTestTimeoutMilliseconds);
+ using QuicConnection serverConnection = serverTask.Result;
+
ReadOnlyMemory<byte> helloWorld = Encoding.ASCII.GetBytes("Hello world!");
ReadOnlySequence<byte> ros = CreateReadOnlySequenceFromBytes(helloWorld.ToArray());
using QuicListener listener = CreateQuicListener();
using QuicConnection clientConnection = CreateQuicConnection(listener.ListenEndPoint);
- ValueTask clientTask = clientConnection.ConnectAsync();
- using QuicConnection serverConnection = await listener.AcceptConnectionAsync();
- await clientTask;
+ Task<QuicConnection> serverTask = listener.AcceptConnectionAsync().AsTask();
+ await TaskTimeoutExtensions.WhenAllOrAnyFailed(clientConnection.ConnectAsync().AsTask(), serverTask, PassingTestTimeoutMilliseconds);
+ using QuicConnection serverConnection = serverTask.Result;
using QuicStream clientStream = clientConnection.OpenBidirectionalStream();
Assert.Equal(0, clientStream.StreamId);
using QuicListener listener = CreateQuicListener();
using QuicConnection clientConnection = CreateQuicConnection(listener.ListenEndPoint);
- ValueTask clientTask = clientConnection.ConnectAsync();
- using QuicConnection serverConnection = await listener.AcceptConnectionAsync();
- await clientTask;
+ Task<QuicConnection> serverTask = listener.AcceptConnectionAsync().AsTask();
+ await TaskTimeoutExtensions.WhenAllOrAnyFailed(clientConnection.ConnectAsync().AsTask(), serverTask, PassingTestTimeoutMilliseconds);
+ using QuicConnection serverConnection = serverTask.Result;
using QuicStream clientStream = clientConnection.OpenBidirectionalStream();
Assert.Equal(0, clientStream.StreamId);
byte[] buffer = new byte[100];
QuicConnectionAbortedException ex = await Assert.ThrowsAsync<QuicConnectionAbortedException>(() => serverStream.ReadAsync(buffer).AsTask());
Assert.Equal(ExpectedErrorCode, ex.ErrorCode);
- }).WaitAsync(TimeSpan.FromSeconds(5));
+ }).WaitAsync(TimeSpan.FromMilliseconds(PassingTestTimeoutMilliseconds));
}
[Fact]
byte[] buffer = new byte[100];
await Assert.ThrowsAsync<QuicOperationAbortedException>(() => serverStream.ReadAsync(buffer).AsTask());
- }).WaitAsync(TimeSpan.FromSeconds(5));
+ }).WaitAsync(TimeSpan.FromMilliseconds(PassingTestTimeoutMilliseconds));
}
}
}
{
const int ExpectedErrorCode = 1234;
+ public QuicConnectionTests(ITestOutputHelper output) : base(output) { }
+
[Fact]
public async Task TestConnect()
{
}
}
- public sealed class QuicConnectionTests_MockProvider : QuicConnectionTests<MockProviderFactory> { }
+ public sealed class QuicConnectionTests_MockProvider : QuicConnectionTests<MockProviderFactory>
+ {
+ public QuicConnectionTests_MockProvider(ITestOutputHelper output) : base(output) { }
+ }
[ConditionalClass(typeof(QuicTestBase<MsQuicProviderFactory>), nameof(QuicTestBase<MsQuicProviderFactory>.IsSupported))]
- public sealed class QuicConnectionTests_MsQuicProvider : QuicConnectionTests<MsQuicProviderFactory> { }
+ public sealed class QuicConnectionTests_MsQuicProvider : QuicConnectionTests<MsQuicProviderFactory>
+ {
+ public QuicConnectionTests_MsQuicProvider(ITestOutputHelper output) : base(output) { }
+ }
}
using System.Threading.Tasks;
using Xunit;
+using Xunit.Abstractions;
namespace System.Net.Quic.Tests
{
public abstract class QuicListenerTests<T> : QuicTestBase<T>
where T : IQuicImplProviderFactory, new()
{
+ public QuicListenerTests(ITestOutputHelper output) : base(output) { }
+
[Fact]
public async Task Listener_Backlog_Success()
{
}
}
- public sealed class QuicListenerTests_MockProvider : QuicListenerTests<MockProviderFactory> { }
+ public sealed class QuicListenerTests_MockProvider : QuicListenerTests<MockProviderFactory>
+ {
+ public QuicListenerTests_MockProvider(ITestOutputHelper output) : base(output) { }
+ }
[ConditionalClass(typeof(QuicTestBase<MsQuicProviderFactory>), nameof(QuicTestBase<MsQuicProviderFactory>.IsSupported))]
- public sealed class QuicListenerTests_MsQuicProvider : QuicListenerTests<MsQuicProviderFactory> { }
+ public sealed class QuicListenerTests_MsQuicProvider : QuicListenerTests<MsQuicProviderFactory>
+ {
+ public QuicListenerTests_MsQuicProvider(ITestOutputHelper output) : base(output) { }
+ }
}
using System.Collections.Generic;
using System.IO;
using System.IO.Tests;
+using System.Net.Sockets;
using System.Net.Quic.Implementations;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
+using System.Threading;
using System.Threading.Tasks;
using Xunit;
+using Xunit.Abstractions;
namespace System.Net.Quic.Tests
{
protected override QuicImplementationProvider Provider => QuicImplementationProviders.MsQuic;
protected override bool UsableAfterCanceledReads => false;
protected override bool BlocksOnZeroByteReads => true;
+
+ public MsQuicQuicStreamConformanceTests(ITestOutputHelper output)
+ {
+ _output = output;
+ }
}
public abstract class QuicStreamConformanceTests : ConnectedStreamConformanceTests
{
public X509Certificate2 ServerCertificate = System.Net.Test.Common.Configuration.Certificates.GetServerCertificate();
+ public ITestOutputHelper _output;
public bool RemoteCertificateValidationCallback(object sender, X509Certificate? certificate, X509Chain? chain, SslPolicyErrors sslPolicyErrors)
{
}),
Task.Run(async () =>
{
- connection2 = new QuicConnection(
- provider,
- listener.ListenEndPoint,
- GetSslClientAuthenticationOptions());
- await connection2.ConnectAsync();
- stream2 = connection2.OpenBidirectionalStream();
- // OpenBidirectionalStream only allocates ID. We will force stream opening
- // by Writing there and receiving data on the other side.
- await stream2.WriteAsync(buffer);
+ try
+ {
+ connection2 = new QuicConnection(
+ provider,
+ listener.ListenEndPoint,
+ GetSslClientAuthenticationOptions());
+ await connection2.ConnectAsync();
+ stream2 = connection2.OpenBidirectionalStream();
+ // OpenBidirectionalStream only allocates ID. We will force stream opening
+ // by Writing there and receiving data on the other side.
+ await stream2.WriteAsync(buffer);
+ }
+ catch (Exception ex)
+ {
+ _output?.WriteLine($"Failed to {ex.Message}");
+ throw;
+ }
}));
+ // No need to keep the listener once we have connected connection and streams
+ listener.Dispose();
+
var result = new StreamPairWithOtherDisposables(stream1, stream2);
result.Disposables.Add(connection1);
result.Disposables.Add(connection2);
- result.Disposables.Add(listener);
return result;
}
using System.Threading;
using System.Threading.Tasks;
using Xunit;
+using Xunit.Abstractions;
namespace System.Net.Quic.Tests
{
where T : IQuicImplProviderFactory, new()
{
private static byte[] s_data = Encoding.UTF8.GetBytes("Hello world!");
+ public QuicStreamTests(ITestOutputHelper output) : base(output) { }
[Fact]
public async Task BasicTest()
[Fact]
public async Task MultipleReadsAndWrites()
{
+ using CancellationTokenSource cts = new CancellationTokenSource();
+ cts.CancelAfter(PassingTestTimeout);
const int sendCount = 5;
int expectedBytesCount = s_data.Length * sendCount;
byte[] expected = new byte[expectedBytesCount];
iterations: 100,
serverFunction: async connection =>
{
- await using QuicStream stream = await connection.AcceptStreamAsync();
+ await using QuicStream stream = await connection.AcceptStreamAsync(cts.Token);
byte[] buffer = new byte[expectedBytesCount];
int bytesRead = await ReadAll(stream, buffer);
{
await stream.WriteAsync(s_data);
}
- await stream.WriteAsync(Memory<byte>.Empty, endStream: true);
+ await stream.WriteAsync(Memory<byte>.Empty, endStream: true, cts.Token);
- await stream.ShutdownCompleted();
+ await stream.ShutdownCompleted(cts.Token);
},
clientFunction: async connection =>
{
for (int i = 0; i < sendCount; i++)
{
- await stream.WriteAsync(s_data);
+ await stream.WriteAsync(s_data, cts.Token);
}
- await stream.WriteAsync(Memory<byte>.Empty, endStream: true);
+ await stream.WriteAsync(Memory<byte>.Empty, endStream: true, cts.Token);
byte[] buffer = new byte[expectedBytesCount];
int bytesRead = await ReadAll(stream, buffer);
Assert.Equal(expectedBytesCount, bytesRead);
Assert.Equal(expected, buffer);
- await stream.ShutdownCompleted();
+ await stream.ShutdownCompleted(cts.Token);
}
);
}
}
}
- public sealed class QuicStreamTests_MockProvider : QuicStreamTests<MockProviderFactory> { }
+ public sealed class QuicStreamTests_MockProvider : QuicStreamTests<MockProviderFactory>
+ {
+ public QuicStreamTests_MockProvider(ITestOutputHelper output) : base(output) { }
+ }
[ConditionalClass(typeof(QuicTestBase<MsQuicProviderFactory>), nameof(QuicTestBase<MsQuicProviderFactory>.IsSupported))]
- public sealed class QuicStreamTests_MsQuicProvider : QuicStreamTests<MsQuicProviderFactory> { }
+ public sealed class QuicStreamTests_MsQuicProvider : QuicStreamTests<MsQuicProviderFactory>
+ {
+ public QuicStreamTests_MsQuicProvider(ITestOutputHelper output) : base(output) { }
+ }
}
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
+using System.Diagnostics;
using System.Net.Quic.Implementations;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
+using Xunit.Abstractions;
using System.Diagnostics.Tracing;
namespace System.Net.Quic.Tests
public X509Certificate2 ServerCertificate = System.Net.Test.Common.Configuration.Certificates.GetServerCertificate();
public X509Certificate2 ClientCertificate = System.Net.Test.Common.Configuration.Certificates.GetClientCertificate();
+ public ITestOutputHelper _output;
public const int PassingTestTimeoutMilliseconds = 4 * 60 * 1000;
public static TimeSpan PassingTestTimeout => TimeSpan.FromMilliseconds(PassingTestTimeoutMilliseconds);
+ public QuicTestBase(ITestOutputHelper output)
+ {
+ _output = output;
+ }
public bool RemoteCertificateValidationCallback(object sender, X509Certificate? certificate, X509Chain? chain, SslPolicyErrors sslPolicyErrors)
{
Assert.Equal(ServerCertificate.GetCertHash(), certificate?.GetCertHash());
return CreateQuicListener(options);
}
+ internal async Task<(QuicConnection, QuicConnection)> CreateConnectedQuicConnection()
+ {
+ using QuicListener listener = CreateQuicListener();
+ QuicConnection clientConnection = CreateQuicConnection(listener.ListenEndPoint);
+
+ ValueTask clientTask = clientConnection.ConnectAsync();
+ ValueTask<QuicConnection> serverTask = listener.AcceptConnectionAsync();
+ await new Task[] { clientTask.AsTask(), serverTask.AsTask() }.WhenAllOrAnyFailed(PassingTestTimeoutMilliseconds);
+ return (clientConnection, serverTask.Result);
+ }
+
internal async Task PingPong(QuicConnection client, QuicConnection server)
{
using QuicStream clientStream = client.OpenBidirectionalStream();
private QuicListener CreateQuicListener(QuicListenerOptions options) => new QuicListener(ImplementationProvider, options);
- internal async Task RunClientServer(Func<QuicConnection, Task> clientFunction, Func<QuicConnection, Task> serverFunction, int iterations = 1, int millisecondsTimeout = 30_000, QuicListenerOptions listenerOptions = null)
+ internal async Task RunClientServer(Func<QuicConnection, Task> clientFunction, Func<QuicConnection, Task> serverFunction, int iterations = 1, int millisecondsTimeout = PassingTestTimeoutMilliseconds, QuicListenerOptions listenerOptions = null)
{
const long ClientCloseErrorCode = 11111;
const long ServerCloseErrorCode = 22222;
{
Task.Run(async () =>
{
- using QuicConnection serverConnection = await listener.AcceptConnectionAsync();
+ using QuicConnection serverConnection = await listener.AcceptConnectionAsync().AsTask().WaitAsync(millisecondsTimeout);
await serverFunction(serverConnection);
serverFinished.Release();
Task.Run(async () =>
{
using QuicConnection clientConnection = CreateQuicConnection(listener.ListenEndPoint);
- await clientConnection.ConnectAsync();
+ try
+ {
+ await clientConnection.ConnectAsync();
+ }
+ catch (Exception ex)
+ {
+ _output?.WriteLine("Failed to connect {0} with {1}", listener.ListenEndPoint, ex.Message);
+ throw;
+ }
+
await clientFunction(clientConnection);
clientFinished.Release();
);
}
- internal Task RunBidirectionalClientServer(Func<QuicStream, Task> clientFunction, Func<QuicStream, Task> serverFunction, int iterations = 1, int millisecondsTimeout = 30_000)
+ internal Task RunBidirectionalClientServer(Func<QuicStream, Task> clientFunction, Func<QuicStream, Task> serverFunction, int iterations = 1, int millisecondsTimeout = PassingTestTimeoutMilliseconds)
=> RunStreamClientServer(clientFunction, serverFunction, bidi: true, iterations, millisecondsTimeout);
- internal Task RunUnirectionalClientServer(Func<QuicStream, Task> clientFunction, Func<QuicStream, Task> serverFunction, int iterations = 1, int millisecondsTimeout = 30_000)
+ internal Task RunUnirectionalClientServer(Func<QuicStream, Task> clientFunction, Func<QuicStream, Task> serverFunction, int iterations = 1, int millisecondsTimeout = PassingTestTimeoutMilliseconds)
=> RunStreamClientServer(clientFunction, serverFunction, bidi: false, iterations, millisecondsTimeout);
internal static async Task<int> ReadAll(QuicStream stream, byte[] buffer)