using Lutra.Application.Interfaces; using Lutra.Infrastructure.Sql; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; namespace Lutra.API.IntegrationTests.Infrastructure; /// /// Custom WebApplicationFactory that replaces the PostgreSQL database with SQLite in-memory /// so that integration tests can run without a live database server. /// A single SqliteConnection is kept open for the lifetime of the factory so that /// all DI scopes share the same in-memory database. /// public class LutraApiFactory : WebApplicationFactory { // Opened immediately so it is ready when ConfigureWebHost runs. private readonly SqliteConnection _connection = new("Data Source=:memory:"); private bool _schemaCreated; public LutraApiFactory() { _connection.Open(); } /// Ensures the SQLite schema is created. Call once before the first test. public void EnsureSchemaCreated() { if (_schemaCreated) return; using var scope = Services.CreateScope(); var db = (LutraDbContext)scope.ServiceProvider.GetRequiredService(); db.Database.EnsureCreated(); _schemaCreated = true; } protected override void ConfigureWebHost(IWebHostBuilder builder) { builder.ConfigureServices(services => { // EF Core 10 stores provider configuration in IDbContextOptionsConfiguration // descriptors (one per AddDbContext call). All four registration types must be // removed so neither Npgsql options nor its provider services survive into the // SQLite registration. services.RemoveAll(); services.RemoveAll(); services.RemoveAll>(); services.RemoveAll(); services.RemoveAll(typeof(IDbContextOptionsConfiguration)); // Register SQLite using the shared open connection. services.AddDbContext(options => options.UseSqlite(_connection)); }); builder.UseEnvironment("Testing"); } protected override void Dispose(bool disposing) { base.Dispose(disposing); if (disposing) _connection.Dispose(); } }