using Npgsql; using Testcontainers.PostgreSql; namespace GmRelay.Bot.Tests.Features.Sessions.CreateSession.Wizard; [CollectionDefinition(Name)] public sealed class WizardDraftRepositoryCollection : ICollectionFixture { public const string Name = "Wizard draft repository PostgreSQL"; } public sealed class WizardDraftRepositoryFixture : IAsyncLifetime { private static readonly TimeSpan ContainerTimeout = TimeSpan.FromMinutes(2); private readonly PostgreSqlContainer container = new PostgreSqlBuilder("postgres:17-alpine").Build(); public Task InitializeAsync() { return container.StartAsync().WaitAsync(ContainerTimeout); } public Task DisposeAsync() { return container.DisposeAsync().AsTask().WaitAsync(ContainerTimeout); } public async Task CreateSchemaDatabaseAsync() { var databaseName = $"wizard_drafts_{Guid.NewGuid():N}"; await using (var adminConnection = new NpgsqlConnection(container.GetConnectionString())) { await adminConnection.OpenAsync().WaitAsync(ContainerTimeout); await using var createDatabase = new NpgsqlCommand($"CREATE DATABASE \"{databaseName}\"", adminConnection); await createDatabase.ExecuteNonQueryAsync().WaitAsync(ContainerTimeout); } var connectionString = new NpgsqlConnectionStringBuilder(container.GetConnectionString()) { Database = databaseName, Timeout = 10, CommandTimeout = 10 }.ConnectionString; await using (var connection = new NpgsqlConnection(connectionString)) { await connection.OpenAsync().WaitAsync(ContainerTimeout); await using var createSchema = new NpgsqlCommand( """ CREATE TABLE wizard_drafts ( id UUID PRIMARY KEY, chat_id BIGINT NOT NULL, message_thread_id INT, owner_telegram_id BIGINT NOT NULL, step TEXT NOT NULL, payload JSONB NOT NULL, draft_message_id BIGINT, created_at TIMESTAMPTZ NOT NULL, updated_at TIMESTAMPTZ NOT NULL, expires_at TIMESTAMPTZ NOT NULL ); CREATE INDEX idx_wizard_drafts_owner ON wizard_drafts(chat_id, message_thread_id, owner_telegram_id); CREATE INDEX idx_wizard_drafts_expires ON wizard_drafts(expires_at); """, connection); await createSchema.ExecuteNonQueryAsync().WaitAsync(ContainerTimeout); } return connectionString; } }