Why won't unit tests connect to a websocket

Viewed 233

UPDATE: I've uploaded a repo - https://github.com/mrpmorris/CannotIntegrationTestWebApp/blob/master/TestProject1/UnitTest1.cs

I have a web server that serves both HTTPS and WebSocket requests. When I run the app I am able to connect and make requests from postman for both HTTPS://localhost:8080 and WSS://localhost:8080/game-server

using Gambit.ApplicationLayer;
using Gambit.GameServer.Configuration;
using Gambit.GameServer.UseCases;

namespace Gambit.GameServer;

public class Program
{
    public static async Task Main(string[] args)
    {
        WebApplication app = BuildApp(args);
        await RunAppAsync(app);
    }

    public static WebApplication BuildApp(string[] args, Action<WebApplicationBuilder>? configure = null)
    {
        WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
        IServiceCollection services = builder.Services;
        IConfiguration configuration = builder.Configuration;
        IWebHostEnvironment environment = builder.Environment;

        services.AddControllers();
        services.AddLogging(opts =>
        {
            opts.ClearProviders();
            opts.AddConfiguration(configuration.GetSection("Logging"));
            opts.AddDebug();
            opts.AddEventSourceLogger();
#if DEBUG
            if (environment.IsDevelopment())
                opts.AddConsole();
#endif
        });
        services.Configure<GameServerOptions>(configuration.GetSection("GameServer"));
        services.AddApplicationServices(configuration);

        configure?.Invoke(builder);
        WebApplication app = builder.Build();
        return app;
    }

    public static async Task RunAppAsync(WebApplication app)
    {
        app.MapGet("/", () => "Gambit.Server.API is running");
        app.AddUserUseCases();
        app.AddGameUseCases();
        app.MapControllers();
        app.UseWebSockets();
        await app.RunAsync();
    }
}

When I run my unit tests I use the same code to create and run the server (once per test run) my tests are able to make HTTPS requests but not connect via a WebSocket. When I try, I get a 404 error. I experience the same in PostMan.

    static IntegrationTestsServer()
    {
        ConfigureMocks();
        Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "IntegrationTesting");
        var app = Program.BuildApp(Array.Empty<string>(), builder =>
        {
            builder.WebHost.UseSetting("urls", "https://localhost:8080");
        });

        Configuration = app.Services.GetRequiredService<IConfiguration>();
        GameServerOptions = app.Services.GetRequiredService<IOptions<GameServerOptions>>();
        var dbContextOptions = app.Services.GetRequiredService<DbContextOptions<ApplicationDbContext>>();
        using var dbContext = new ApplicationDbContext(dbContextOptions);
        dbContext.Database.EnsureDeleted();
        dbContext.Database.EnsureCreated();
        HttpClient = new HttpClient { BaseAddress = new Uri("https://localhost:8080") };
        _ = Program.RunAppAsync(app);
    }

I can even perform a successful HttpClient.GetAsync("https://localhost:8080") immediately before the ClientWebSocket fails

System.Net.WebSockets.WebSocketException : The server returned status code '404' when status code '101' was expected.

Does anyone have any ideas why this might be?

1 Answers

Set ApplicationName in the WebApplicationOptions sent to WebApplication.CreateBuilder

WebApplication.CreateBuilder
(
  new WebApplicationOptions
  {
    ApplicationName = typeof(Gambit.GameServer.Program).Assembly.GetName().Name // <== 
  }
);

Now it will be able to find your manifest file when running from a test.

See the following blog post for more of the back story on how I figured it out.

https://thefreezeteam.com/posts/StevenTCramer/2022/08/25/runwebserverintest

Related