diff --git a/src/SignalR/clients/csharp/Client/test/FunctionalTests/HubConnectionTests.cs b/src/SignalR/clients/csharp/Client/test/FunctionalTests/HubConnectionTests.cs index 533bea20e523..edb2bd5f5385 100644 --- a/src/SignalR/clients/csharp/Client/test/FunctionalTests/HubConnectionTests.cs +++ b/src/SignalR/clients/csharp/Client/test/FunctionalTests/HubConnectionTests.cs @@ -2361,47 +2361,80 @@ public async Task CanBlockOnAsyncOperationsWithOneAtATimeSynchronizationContext( } [ConditionalFact] - [QuarantinedTest("https://github.com/dotnet/aspnetcore/issues/50180")] public async Task LongPollingUsesHttp2ByDefault() { - await using (var server = await StartServer(configureKestrelServerOptions: o => + var logsSeen = false; + var logsTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + + Action handler = null; + handler = context => { - o.ConfigureEndpointDefaults(o2 => + if (logsSeen) { - o2.Protocols = Server.Kestrel.Core.HttpProtocols.Http1AndHttp2; - o2.UseHttps(); - }); - o.ConfigureHttpsDefaults(httpsOptions => + return; + } + + var message = context.Message; + if ((message.Contains("Request starting HTTP/2 POST") && message.Contains("/negotiate?")) || + (message.Contains("Request starting HTTP/2 POST") && message.Contains("?id=")) || + (message.Contains("Request finished HTTP/2 GET") && message.Contains("?id=")) || + (message.Contains("Request finished HTTP/2 DELETE") && message.Contains("?id="))) { - httpsOptions.ServerCertificate = TestCertificateHelper.GetTestCert(); - }); - })) + logsSeen = true; + logsTcs.TrySetResult(); + } + }; + + TestSink.MessageLogged += handler; + + try { - var hubConnection = new HubConnectionBuilder() - .WithLoggerFactory(LoggerFactory) - .WithUrl(server.Url + "/default", HttpTransportType.LongPolling, o => o.HttpMessageHandlerFactory = h => + await using (var server = await StartServer(configureKestrelServerOptions: o => + { + o.ConfigureEndpointDefaults(o2 => { - ((HttpClientHandler)h).ServerCertificateCustomValidationCallback = (_, _, _, _) => true; - return h; - }) - .Build(); - try + o2.Protocols = Server.Kestrel.Core.HttpProtocols.Http1AndHttp2; + o2.UseHttps(); + }); + o.ConfigureHttpsDefaults(httpsOptions => + { + httpsOptions.ServerCertificate = TestCertificateHelper.GetTestCert(); + }); + })) { - await hubConnection.StartAsync().DefaultTimeout(); - var httpProtocol = await hubConnection.InvokeAsync(nameof(TestHub.GetHttpProtocol)).DefaultTimeout(); + var hubConnection = new HubConnectionBuilder() + .WithLoggerFactory(LoggerFactory) + .WithUrl(server.Url + "/default", HttpTransportType.LongPolling, o => o.HttpMessageHandlerFactory = h => + { + ((HttpClientHandler)h).ServerCertificateCustomValidationCallback = (_, _, _, _) => true; + return h; + }) + .Build(); + try + { + await hubConnection.StartAsync().DefaultTimeout(); + var httpProtocol = await hubConnection.InvokeAsync(nameof(TestHub.GetHttpProtocol)).DefaultTimeout(); - Assert.Equal("HTTP/2", httpProtocol); - } - catch (Exception ex) - { - LoggerFactory.CreateLogger().LogError(ex, "{ExceptionType} from test", ex.GetType().FullName); - throw; - } - finally - { - await hubConnection.DisposeAsync().DefaultTimeout(); + Assert.Equal("HTTP/2", httpProtocol); + + // Wait for HTTP/2 logs to flush before server disposal + await logsTcs.Task.DefaultTimeout(); + } + catch (Exception ex) + { + LoggerFactory.CreateLogger().LogError(ex, "{ExceptionType} from test", ex.GetType().FullName); + throw; + } + finally + { + await hubConnection.DisposeAsync().DefaultTimeout(); + } } } + finally + { + TestSink.MessageLogged -= handler; + } // negotiate is HTTP2 Assert.Contains(TestSink.Writes, context => context.Message.Contains("Request starting HTTP/2 POST") && context.Message.Contains("/negotiate?"));