using System.Security.Cryptography; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc.Testing; using SQLInsight.Hub; using SQLInsight.Licensing; using Testcontainers.PostgreSql; namespace SQLInsight.IntegrationTests; /// /// SQLInsight Hub in-process on a real PostgreSQL, with a test signing key the hub trusts. /// public sealed class HubFixture : IAsyncLifetime { public const string KeyId = "itest"; private readonly PostgreSqlContainer _postgres = new PostgreSqlBuilder("postgres:17-alpine").Build(); private readonly ECDsa _key = ECDsa.Create(ECCurve.NamedCurves.nistP256); public WebApplicationFactory Factory { get; private set; } = null!; public string PublicKey => Convert.ToBase64String(_key.ExportSubjectPublicKeyInfo()); public string ConnectionString => _postgres.GetConnectionString(); public async Task InitializeAsync() { await _postgres.StartAsync(); Factory = new WebApplicationFactory().WithWebHostBuilder(b => { b.UseEnvironment("Development"); b.UseSetting("ConnectionStrings:Hub", ConnectionString); b.UseSetting($"SQLInsight:Hub:TrustedKeys:{KeyId}", PublicKey); b.UseSetting("SQLInsight:Hub:LoginAttemptsPerMinute", "1000"); }); await HubProgram.MigrateAsync(Factory.Services); } public string License(string customer, LicensePlan plan = LicensePlan.Professional, int maxInstances = 0, DateTimeOffset? expires = null, string? id = null) => SignedDocument.Sign(new License { LicenseId = id ?? Guid.NewGuid().ToString("N"), Customer = customer, Plan = plan, IssuedAt = DateTimeOffset.UtcNow.AddDays(-1), ExpiresAt = expires ?? DateTimeOffset.UtcNow.AddYears(1), MaxInstances = maxInstances, KeyId = KeyId, }, _key); public async Task DisposeAsync() { await Factory.DisposeAsync(); await _postgres.DisposeAsync(); _key.Dispose(); } }