quic test improvements (#56043)
authorTomas Weinfurt <tweinfurt@yahoo.com>
Tue, 27 Jul 2021 01:36:38 +0000 (18:36 -0700)
committerGitHub <noreply@github.com>
Tue, 27 Jul 2021 01:36:38 +0000 (18:36 -0700)
* quic test improvements

* fix incorrect use of PassingTestTimeout

* feedback from review

src/libraries/Common/tests/StreamConformanceTests/StreamConformanceTests.csproj
src/libraries/Common/tests/System/Threading/Tasks/TaskTimeoutExtensions.cs
src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs
src/libraries/System.Net.Quic/tests/FunctionalTests/QuicConnectionTests.cs
src/libraries/System.Net.Quic/tests/FunctionalTests/QuicListenerTests.cs
src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamConnectedStreamConformanceTests.cs
src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamTests.cs
src/libraries/System.Net.Quic/tests/FunctionalTests/QuicTestBase.cs

index b5dfa85..6959f41 100644 (file)
@@ -4,7 +4,7 @@
     <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" />
index 2efde1f..2efa7af 100644 (file)
@@ -12,6 +12,9 @@ namespace System.Threading.Tasks
         #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);
 
@@ -28,6 +31,9 @@ namespace System.Threading.Tasks
             }
         }
 
+        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);
 
@@ -48,6 +54,9 @@ namespace System.Threading.Tasks
         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
index a85132a..a54b2bc 100644 (file)
@@ -20,23 +20,19 @@ namespace System.Net.Quic.Tests
     [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());
         }
@@ -55,10 +51,10 @@ namespace System.Net.Quic.Tests
             };
 
             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());
@@ -112,10 +108,9 @@ namespace System.Net.Quic.Tests
             };
 
             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]
@@ -342,10 +337,10 @@ namespace System.Net.Quic.Tests
             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.
@@ -359,10 +354,9 @@ namespace System.Net.Quic.Tests
         {
             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.
@@ -387,9 +381,9 @@ namespace System.Net.Quic.Tests
             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);
@@ -425,16 +419,15 @@ namespace System.Net.Quic.Tests
             };
 
             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(
@@ -530,9 +523,10 @@ namespace System.Net.Quic.Tests
             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());
@@ -714,9 +708,9 @@ namespace System.Net.Quic.Tests
                 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);
@@ -737,9 +731,9 @@ namespace System.Net.Quic.Tests
                 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);
@@ -781,7 +775,7 @@ namespace System.Net.Quic.Tests
                 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]
@@ -807,7 +801,7 @@ namespace System.Net.Quic.Tests
 
                 byte[] buffer = new byte[100];
                 await Assert.ThrowsAsync<QuicOperationAbortedException>(() => serverStream.ReadAsync(buffer).AsTask());
-            }).WaitAsync(TimeSpan.FromSeconds(5));
+            }).WaitAsync(TimeSpan.FromMilliseconds(PassingTestTimeoutMilliseconds));
         }
     }
 }
index b8c91f4..9f7010f 100644 (file)
@@ -13,6 +13,8 @@ namespace System.Net.Quic.Tests
     {
         const int ExpectedErrorCode = 1234;
 
+        public QuicConnectionTests(ITestOutputHelper output) : base(output) { }
+
         [Fact]
         public async Task TestConnect()
         {
@@ -285,8 +287,14 @@ namespace System.Net.Quic.Tests
         }
     }
 
-    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) { }
+    }
 }
index 3eb016b..642f6bd 100644 (file)
@@ -3,12 +3,15 @@
 
 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()
         {
@@ -25,8 +28,14 @@ namespace System.Net.Quic.Tests
         }
     }
 
-    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) { }
+    }
 }
index 4ca6e0e..9ba6c5a 100644 (file)
@@ -4,11 +4,14 @@
 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
 {
@@ -23,11 +26,17 @@ 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)
         {
@@ -75,21 +84,31 @@ namespace System.Net.Quic.Tests
                 }),
                 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;
         }
index af45e79..40b43fd 100644 (file)
@@ -9,6 +9,7 @@ using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
 using Xunit;
+using Xunit.Abstractions;
 
 namespace System.Net.Quic.Tests
 {
@@ -16,6 +17,7 @@ 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()
@@ -55,6 +57,8 @@ namespace System.Net.Quic.Tests
         [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];
@@ -69,7 +73,7 @@ namespace System.Net.Quic.Tests
                 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);
@@ -80,9 +84,9 @@ namespace System.Net.Quic.Tests
                     {
                         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 =>
                 {
@@ -90,16 +94,16 @@ namespace System.Net.Quic.Tests
 
                     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);
                 }
             );
         }
@@ -677,8 +681,14 @@ namespace System.Net.Quic.Tests
         }
     }
 
-    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) { }
+    }
 }
index 24a653c..2a03bca 100644 (file)
@@ -2,6 +2,7 @@
 // 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;
@@ -9,6 +10,7 @@ using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
 using Xunit;
+using Xunit.Abstractions;
 using System.Diagnostics.Tracing;
 
 namespace System.Net.Quic.Tests
@@ -31,9 +33,14 @@ 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());
@@ -92,6 +99,17 @@ namespace System.Net.Quic.Tests
             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();
@@ -124,7 +142,7 @@ namespace System.Net.Quic.Tests
 
         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;
@@ -140,7 +158,7 @@ namespace System.Net.Quic.Tests
                 {
                     Task.Run(async () =>
                     {
-                        using QuicConnection serverConnection = await listener.AcceptConnectionAsync();
+                        using QuicConnection serverConnection = await listener.AcceptConnectionAsync().AsTask().WaitAsync(millisecondsTimeout);
                         await serverFunction(serverConnection);
 
                         serverFinished.Release();
@@ -150,7 +168,16 @@ namespace System.Net.Quic.Tests
                     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();
@@ -193,10 +220,10 @@ namespace System.Net.Quic.Tests
             );
         }
 
-        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)