using System.Net; using System.Net.Http.Headers; using System.Net.Http.Json; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using SQLInsight.Hub.Data; using SQLInsight.Hub.Maintenance; namespace SQLInsight.IntegrationTests; [Trait("Category", "Integration")] public class HubMaintenanceTests(HubFixture hub) : IClassFixture { private async Task SubmitAsync(string license, params (string Rule, string Subject, string Severity)[] findings) { using var request = new HttpRequestMessage(HttpMethod.Post, "/api/v1/findings") { Content = JsonContent.Create(HubApiTests.Submission("sql01", DateTimeOffset.UtcNow, findings)), }; request.Headers.Authorization = new AuthenticationHeaderValue("SQLInsight-License", license); return (await hub.Factory.CreateClient().SendAsync(request)).StatusCode; } private async Task WithDbAsync(Func> action) { await using var scope = hub.Factory.Services.CreateAsyncScope(); return await action(scope.ServiceProvider.GetRequiredService(), scope.ServiceProvider.GetRequiredService()); } [Fact] public async Task Deleting_a_customer_removes_its_data_and_blocks_its_licenses() { var name = $"Slet {Guid.NewGuid():N}"[..20]; var license = hub.License(name); Assert.Equal(HttpStatusCode.OK, await SubmitAsync(license, ("SQLI-DB-007", "database: Sales", "Critical"))); var deleted = await WithDbAsync((_, m) => m.DeleteCustomerAsync(name)); Assert.True(deleted); var (customers, findings, instances, revoked) = await WithDbAsync(async (db, _) => ( await db.Customers.CountAsync(c => c.Name == name), await db.Findings.CountAsync(f => f.Instance!.Customer!.Name == name), await db.Instances.CountAsync(i => i.Customer!.Name == name), await db.Licenses.Where(l => l.Customer!.Name.StartsWith("Slettet kunde #")).CountAsync(l => l.RevokedAt != null))); Assert.Equal(0, customers); Assert.Equal(0, findings); Assert.Equal(0, instances); Assert.True(revoked >= 1); Assert.Equal(HttpStatusCode.Forbidden, await SubmitAsync(license, ("SQLI-DB-007", "database: Sales", "Critical"))); } [Fact] public async Task Retention_removes_old_resolved_findings_old_submissions_and_silent_instances() { var active = $"Aktiv {Guid.NewGuid():N}"[..20]; var silent = $"Tavs {Guid.NewGuid():N}"[..20]; await SubmitAsync(hub.License(active), ("SQLI-CFG-001", "", "High"), ("SQLI-DB-007", "database: A", "Critical")); await SubmitAsync(hub.License(silent), ("SQLI-CFG-001", "", "High")); await WithDbAsync(async (db, _) => { var old = DateTime.UtcNow.AddDays(-400); await db.Findings.Where(f => f.Instance!.Customer!.Name == active && f.RuleId == "SQLI-DB-007") .ExecuteUpdateAsync(f => f.SetProperty(x => x.ResolvedAt, old)); await db.Submissions.Where(s => db.Instances.Any(i => i.Id == s.InstanceId && i.Customer!.Name == active)) .ExecuteUpdateAsync(s => s.SetProperty(x => x.ReceivedAt, old)); await db.Instances.Where(i => i.Customer!.Name == silent).ExecuteUpdateAsync(i => i.SetProperty(x => x.LastSubmissionAt, old)); return 0; }); var result = await WithDbAsync((_, m) => m.ApplyRetentionAsync()); Assert.True(result.Findings >= 1 && result.Submissions >= 1 && result.Instances >= 1); var (activeFindings, activeSubmissions, silentInstances) = await WithDbAsync(async (db, _) => ( await db.Findings.Where(f => f.Instance!.Customer!.Name == active).Select(f => f.RuleId).ToListAsync(), await db.Submissions.CountAsync(s => db.Instances.Any(i => i.Id == s.InstanceId && i.Customer!.Name == active)), await db.Instances.CountAsync(i => i.Customer!.Name == silent))); Assert.Equal(["SQLI-CFG-001"], activeFindings); Assert.Equal(0, activeSubmissions); Assert.Equal(0, silentInstances); } }