diff --git a/src/Servers/Kestrel/Transport.Quic/test/QuicConnectionContextTests.cs b/src/Servers/Kestrel/Transport.Quic/test/QuicConnectionContextTests.cs index 60f0d70d372553b25abd22456fc91fd7aff8a0be..1b6eb03c7f4f5d933945423660b04a47eeb8c61d 100644 --- a/src/Servers/Kestrel/Transport.Quic/test/QuicConnectionContextTests.cs +++ b/src/Servers/Kestrel/Transport.Quic/test/QuicConnectionContextTests.cs @@ -421,6 +421,8 @@ public class QuicConnectionContextTests : TestApplicationErrorLoggerLoggedTest public async Task StreamPool_StreamAbortedOnClientAndServer_NotPooled() { // Arrange + using var httpEventSource = new HttpEventSourceListener(LoggerFactory); + await using var connectionListener = await QuicTestHelpers.CreateConnectionListenerFactory(LoggerFactory); var options = QuicTestHelpers.CreateClientConnectionOptions(connectionListener.EndPoint); diff --git a/src/Servers/Kestrel/shared/test/ServerRetryHelper.cs b/src/Servers/Kestrel/shared/test/ServerRetryHelper.cs index f61da6aadf63a2eeadf4cb9f5c20aaa38bcdace5..d211dde1fd469d0f99302c049f0c14234a6da378 100644 --- a/src/Servers/Kestrel/shared/test/ServerRetryHelper.cs +++ b/src/Servers/Kestrel/shared/test/ServerRetryHelper.cs @@ -1,33 +1,37 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Net; +using System.Net.Sockets; using Microsoft.Extensions.Logging; namespace Microsoft.AspNetCore.Testing; public static class ServerRetryHelper { + private const int RetryCount = 10; + /// <summary> /// Retry a func. Useful when a test needs an explicit port and you want to avoid port conflicts. /// </summary> public static async Task BindPortsWithRetry(Func<int, Task> retryFunc, ILogger logger) { + var ports = GetFreePorts(RetryCount); + var retryCount = 0; while (true) { - // Approx dynamic port range on Windows and Linux. - var randomPort = Random.Shared.Next(35000, 60000); try { - await retryFunc(randomPort); + await retryFunc(ports[retryCount]); break; } catch (Exception ex) { retryCount++; - if (retryCount >= 5) + if (retryCount >= RetryCount) { throw; } @@ -38,4 +42,35 @@ public static class ServerRetryHelper } } } + + private static int[] GetFreePorts(int count) + { + var sockets = new List<Socket>(); + + for (var i = 0; i < count; i++) + { + // Find a port that's free by binding port 0. + // Note that this port should be free when the test runs, but: + // - Something else could steal it before the test uses it. + // - UDP port with the same number could be in use. + // For that reason, some retries should be available. + var ipEndPoint = new IPEndPoint(IPAddress.Loopback, 0); + var listenSocket = new Socket(ipEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + + listenSocket.Bind(ipEndPoint); + + sockets.Add(listenSocket); + } + + // Ports are calculated upfront. Rebinding with port 0 could result the same port + // being returned for each retry. + var ports = sockets.Select(s => (IPEndPoint)s.LocalEndPoint).Select(ep => ep.Port).ToArray(); + + foreach (var socket in sockets) + { + socket.Dispose(); + } + + return ports; + } } diff --git a/src/Servers/Kestrel/test/Interop.FunctionalTests/Http3/Http3RequestTests.cs b/src/Servers/Kestrel/test/Interop.FunctionalTests/Http3/Http3RequestTests.cs index 9ad930511a5210f03394892c2cc6d99f8582028d..5330bd22d383806879e010b024ad4e99039d30cd 100644 --- a/src/Servers/Kestrel/test/Interop.FunctionalTests/Http3/Http3RequestTests.cs +++ b/src/Servers/Kestrel/test/Interop.FunctionalTests/Http3/Http3RequestTests.cs @@ -228,6 +228,8 @@ public class Http3RequestTests : LoggedTest public async Task POST_ClientSendsOnlyHeaders_RequestReceivedOnServer(HttpProtocols protocol) { // Arrange + using var httpEventSource = new HttpEventSourceListener(LoggerFactory); + var builder = CreateHostBuilder(context => { return Task.CompletedTask;