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();
}
}