File: HttpConnectionManagerTests.cs
Web Access
Project: src\src\Servers\Kestrel\Core\test\Microsoft.AspNetCore.Server.Kestrel.Core.Tests.csproj (Microsoft.AspNetCore.Server.Kestrel.Core.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.AspNetCore.InternalTesting;
using Microsoft.Extensions.Logging;
using Moq;
using Xunit;
 
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests;
 
public class HttpConnectionManagerTests : LoggedTest
{
    [Fact]
    public void UnrootedConnectionsGetRemovedFromHeartbeat()
    {
        var trace = new KestrelTrace(LoggerFactory);
        var connectionId = "0";
        var httpConnectionManager = new ConnectionManager(trace, ResourceCounter.Unlimited);
 
        // Create HttpConnection in inner scope so it doesn't get rooted by the current frame.
        UnrootedConnectionsGetRemovedFromHeartbeatInnerScope(connectionId, httpConnectionManager, trace);
 
        GC.Collect();
        GC.WaitForPendingFinalizers();
 
        var connectionCount = 0;
        httpConnectionManager.Walk(_ => connectionCount++);
 
        Assert.Equal(0, connectionCount);
 
        Assert.Single(TestSink.Writes.Where(c => c.EventId.Name == "ApplicationNeverCompleted"));
    }
 
    [MethodImpl(MethodImplOptions.NoInlining)]
    private void UnrootedConnectionsGetRemovedFromHeartbeatInnerScope(
        string connectionId,
        ConnectionManager httpConnectionManager,
        KestrelTrace trace)
    {
        var serviceContext = new TestServiceContext();
        var mock = new Mock<DefaultConnectionContext>() { CallBase = true };
        mock.Setup(m => m.ConnectionId).Returns(connectionId);
        var transportConnectionManager = new TransportConnectionManager(httpConnectionManager);
        var httpConnection = new KestrelConnection<ConnectionContext>(0, serviceContext, transportConnectionManager, _ => Task.CompletedTask, mock.Object, trace, TestContextFactory.CreateMetricsContext(mock.Object));
        transportConnectionManager.AddConnection(0, httpConnection);
 
        var connectionCount = 0;
        httpConnectionManager.Walk(_ => connectionCount++);
 
        Assert.Equal(1, connectionCount);
        Assert.Empty(TestSink.Writes.Where(c => c.EventId.Name == "ApplicationNeverCompleted"));
 
        // Ensure httpConnection doesn't get GC'd before this point.
        GC.KeepAlive(httpConnection);
    }
}