using Microsoft.EntityFrameworkCore; using Npgsql; using Tnsu.ApprovalRoute.Infrastructure.Persistence; using Xunit; namespace Tnsu.ApprovalRoute.IntegrationTests.Infrastructure; // Отдельная БД на один xUnit-collection (= один тестовый класс) в общем инстансе Postgres. // Тесты внутри класса делят эту БД; разные классы (разные коллекции) получают разные БД. public sealed class PostgresDatabaseFixture : IAsyncLifetime { private readonly string _databaseName = $"tnsu_test_{Guid.NewGuid():N}"; private readonly NpgsqlConnectionStringBuilder _adminConnectionBuilder = new(TestSettings.BaseConnectionString); public string ConnectionString { get; private set; } = string.Empty; public async Task InitializeAsync() { await using (var adminConnection = new NpgsqlConnection(_adminConnectionBuilder.ConnectionString)) { await adminConnection.OpenAsync(); await using var createCommand = new NpgsqlCommand($"CREATE DATABASE \"{_databaseName}\"", adminConnection); await createCommand.ExecuteNonQueryAsync(); } ConnectionString = new NpgsqlConnectionStringBuilder(_adminConnectionBuilder.ConnectionString) { Database = _databaseName }.ConnectionString; var options = new DbContextOptionsBuilder() .UseNpgsql(ConnectionString) .UseSnakeCaseNamingConvention() .Options; await using var db = new ApprovalRouteDbContext(options); await db.Database.MigrateAsync(); } public async Task DisposeAsync() { await using var adminConnection = new NpgsqlConnection(_adminConnectionBuilder.ConnectionString); await adminConnection.OpenAsync(); await using (var terminateCommand = new NpgsqlCommand( """ SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = @databaseName AND pid <> pg_backend_pid(); """, adminConnection)) { terminateCommand.Parameters.AddWithValue("databaseName", _databaseName); await terminateCommand.ExecuteNonQueryAsync(); } await using var dropCommand = new NpgsqlCommand($"DROP DATABASE IF EXISTS \"{_databaseName}\"", adminConnection); await dropCommand.ExecuteNonQueryAsync(); } }