dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.29k stars 9.96k forks source link

TestHost keep the test running infinitely #54347

Open raphaelm22 opened 7 months ago

raphaelm22 commented 7 months ago

Is there an existing issue for this?

Describe the bug

The test keeps running when some exception is thrown on the scope log creation (and the test never ends).

I have used a library that because of its bad behavior/configuration some exceptions is thrown ILogger.BeginScope and as the test keeps running, it makes diagnosing the problem more complex

Expected Behavior

The HttpClient should return InternalServerError.

Steps To Reproduce

On Program.cs:

var app = WebApplication.CreateBuilder(args).Build();
app.MapGet("/hello-world", ([FromServices] ILogger<Program> logger) =>
{
    logger.LogInformation("Starting...");
    return "Hi";
});
app.Run();

On TestClass:

[Fact]
public async Task Test1()
{
    // Arrange
    var client = new CustomWebApplicationFactory()
        .CreateClient();

    // Act
    var result = await client.GetAsync("/hello-world");

    // Assert
    Assert.Equal(HttpStatusCode.InternalServerError, result.StatusCode);
}
internal class CustomWebApplicationFactory : WebApplicationFactory<Program>
{
    protected override void ConfigureWebHost(IWebHostBuilder builder) => builder
        .ConfigureTestServices(services =>
            services.AddLogging(options =>
            {
                options.ClearProviders();
                options.AddProvider(new MyLoggerProvider());
            })
        );
}
internal class MyLoggerProvider : ILoggerProvider
{
    public ILogger CreateLogger(string categoryName) => new MyLogger();
    public void Dispose() { }
}
internal class MyLogger : ILogger
{
    public IDisposable? BeginScope<TState>(TState state) where TState : notnull => throw new Exception("💣💣💣");
    public bool IsEnabled(LogLevel logLevel) => true;
    public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter) { }
}

Exceptions (if any)

No response

.NET Version

8.0.200

Anything else?

Microsoft Visual Studio Professional 2022 (64-bit) - Preview Version 17.10.0 Preview 1.0

.NET SDK:
 Version:           8.0.200
 Commit:            438cab6a9d
 Workload version:  8.0.200-manifests.5638171e

Ambiente de runtime:
 OS Name:     Windows
 OS Version:  10.0.19045
 OS Platform: Windows
 RID:         win-x64
 Base Path:   C:\Program Files\dotnet\sdk\8.0.200\

Cargas de trabalho do .NET instaladas:
Não há cargas de trabalho instaladas para exibir.

Host:
  Version:      8.0.2
  Architecture: x64
  Commit:       1381d5ebd2

.NET SDKs installed:
  7.0.313 [C:\Program Files\dotnet\sdk]
  7.0.406 [C:\Program Files\dotnet\sdk]
  8.0.200 [C:\Program Files\dotnet\sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 6.0.27 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 7.0.16 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 8.0.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.13 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.15 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.27 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 7.0.16 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 8.0.2 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 6.0.13 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.15 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.27 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 7.0.16 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 8.0.2 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

Other architectures found:
  x86   [C:\Program Files (x86)\dotnet]
    registered at [HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\x86\InstallLocation]

Environment variables:
  Not set

global.json file:
  Not found
amcasey commented 7 months ago

Note to repro'ers: per StackOverflow, you'll need to add public partial class Program {} at the end of Program.cs, otherwise the reference in TestClass will bind to an unrelated type and the test won't run properly.

Also, to make the problem a little more explicit, the exception thrown by BeginScope is the difference between the test failing and waiting indefinitely. The relevant callstack is

>   TestProject1.UnitTest1.MyLogger.BeginScope<Microsoft.AspNetCore.Hosting.HostingApplicationDiagnostics.Log.HostingLogScope>(Microsoft.AspNetCore.Hosting.HostingApplicationDiagnostics.Log.HostingLogScope) Line 48  C#
    Microsoft.AspNetCore.Hosting.HostingApplicationDiagnostics.BeginRequest(Microsoft.AspNetCore.Http.HttpContext, Microsoft.AspNetCore.Hosting.HostingApplication.Context) Line 116    C#
    Microsoft.AspNetCore.Hosting.HostingApplication.CreateContext(Microsoft.AspNetCore.Http.Features.IFeatureCollection) Line 83    C#
    Microsoft.AspNetCore.TestHost.ApplicationWrapper<Microsoft.AspNetCore.Hosting.HostingApplication.Context>.Microsoft.AspNetCore.Hosting.Server.IHttpApplication<Microsoft.AspNetCore.Hosting.HostingApplication.Context>.CreateContext(Microsoft.AspNetCore.Http.Features.IFeatureCollection) Line 36    C#
    Microsoft.AspNetCore.TestHost.ApplicationWrapper<Microsoft.AspNetCore.Hosting.HostingApplication.Context>.CreateContext(Microsoft.AspNetCore.Http.Features.IFeatureCollection) Line 31  C#
    Microsoft.AspNetCore.TestHost.HttpContextBuilder.SendAsync.__RunRequestAsync|0() Line 101   C#
    Microsoft.AspNetCore.TestHost.HttpContextBuilder.SendAsync.AnonymousMethod__1(object) Line 163  C#
    System.Threading.ThreadPoolWorkQueue.Dispatch() Line 918    C#
    System.Threading.PortableThreadPool.WorkerThread.WorkerThreadStart() Line 102   C#
amcasey commented 7 months ago

At a guess, I would say that exceptions thrown by this line require some of the same cleanup as code in the immediately following try block.