// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; using Microsoft.AspNetCore.Testing; using Microsoft.AspNetCore.Testing.xunit; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Testing; using Moq; using Xunit; namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests { public class HttpConnectionManagerTests : LoggedTest { // This test causes MemoryPoolBlocks to be finalized which in turn causes an assert failure in debug builds. #if !DEBUG [ConditionalFact] [NoDebuggerCondition] public async Task CriticalErrorLoggedIfApplicationDoesntComplete() { //////////////////////////////////////////////////////////////////////////////////////// // WARNING: This test will fail under a debugger because Task.s_currentActiveTasks // // roots HttpConnection. // //////////////////////////////////////////////////////////////////////////////////////// var logWh = new SemaphoreSlim(0); var appStartedWh = new SemaphoreSlim(0); var mockTrace = new Mock(); mockTrace .Setup(trace => trace.ApplicationNeverCompleted(It.IsAny())) .Callback(() => { logWh.Release(); }); using (var server = new TestServer(context => { appStartedWh.Release(); var tcs = new TaskCompletionSource(); return tcs.Task; }, new TestServiceContext(new LoggerFactory(), mockTrace.Object))) { using (var connection = server.CreateConnection()) { await connection.SendEmptyGet(); Assert.True(await appStartedWh.WaitAsync(TestConstants.DefaultTimeout)); // Close connection without waiting for a response } var logWaitAttempts = 0; for (; !await logWh.WaitAsync(TimeSpan.FromSeconds(1)) && logWaitAttempts < 30; logWaitAttempts++) { GC.Collect(); GC.WaitForPendingFinalizers(); } Assert.True(logWaitAttempts < 10); } } #endif private class NoDebuggerConditionAttribute : Attribute, ITestCondition { public bool IsMet => !Debugger.IsAttached; public string SkipReason => "A debugger is attached."; } } }