using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Testcontainers.PostgreSql; using WorkClub.Infrastructure.Data; namespace WorkClub.Tests.Integration.Infrastructure; public class CustomWebApplicationFactory : WebApplicationFactory where TProgram : class { private readonly PostgreSqlContainer _postgresContainer = new PostgreSqlBuilder() .WithImage("postgres:16-alpine") .WithDatabase("workclub_test") .WithUsername("test") .WithPassword("test") .Build(); protected override void ConfigureWebHost(IWebHostBuilder builder) { // Start container (async wait) _postgresContainer.StartAsync().GetAwaiter().GetResult(); builder.ConfigureAppConfiguration((context, config) => { // Override connection string for tests config.AddInMemoryCollection(new Dictionary { ["ConnectionStrings:DefaultConnection"] = _postgresContainer.GetConnectionString() }); }); builder.ConfigureServices(services => { // Remove existing DbContext registration var descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions)); if (descriptor != null) { services.Remove(descriptor); } // Add Testcontainers DbContext services.AddDbContext(options => options.UseNpgsql(_postgresContainer.GetConnectionString())); // Replace authentication with TestAuthHandler services.RemoveAll(); services.AddAuthentication(defaultScheme: "Test") .AddScheme("Test", options => { }); // Build service provider and run migrations var sp = services.BuildServiceProvider(); using var scope = sp.CreateScope(); var db = scope.ServiceProvider.GetRequiredService(); db.Database.Migrate(); using var conn = new Npgsql.NpgsqlConnection(_postgresContainer.GetConnectionString()); conn.Open(); using var cmd = conn.CreateCommand(); cmd.CommandText = @" DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'rls_test_user') THEN CREATE USER rls_test_user WITH PASSWORD 'rlspass'; GRANT CONNECT ON DATABASE workclub_test TO rls_test_user; GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO rls_test_user; GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO rls_test_user; END IF; END $$; "; cmd.ExecuteNonQuery(); }); builder.UseEnvironment("Test"); } public override async ValueTask DisposeAsync() { await _postgresContainer.DisposeAsync(); await base.DisposeAsync(); } }