using JobTrackerApi.Models; using JobTrackerApi.Services; using JobTrackerApi.Tests.TestSupport; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using Moq; using Xunit; namespace JobTrackerApi.Tests; public class CvImportRetentionTests { [Theory] [InlineData("pending_review", 8, true)] [InlineData("cancelled", 2, true)] [InlineData("failed", 2, true)] [InlineData("pending_review", 2, false)] public async Task Original_sources_have_bounded_retention_and_recent_reviews_survive(string status, int days, bool expires) { var root = Path.Combine(Path.GetTempPath(), "cv-import-retention-" + Guid.NewGuid().ToString("N")); var environment = Mock.Of(e => e.ContentRootPath == root); var paths = new AppPaths(new ConfigurationBuilder().AddInMemoryCollection(new Dictionary { ["Data:Root"] = root }).Build(), environment); try { await using var db = TestHostFactory.CreateInMemoryDb(); var file = Path.Combine(paths.CvArtifactsRoot, "synthetic.pdf"); await File.WriteAllTextAsync(file, "Synthetic source"); var orphanDirectory = Directory.CreateDirectory(Path.Combine(paths.CvArtifactsRoot, "user-1")).FullName; var orphan = Path.Combine(orphanDirectory, "20260101010101-" + Guid.NewGuid().ToString("N") + ".pdf"); await File.WriteAllTextAsync(orphan, "Interrupted upload"); File.SetLastWriteTimeUtc(orphan, DateTime.UtcNow.AddDays(-8)); var unrelated = Path.Combine(orphanDirectory, "unrelated.pdf"); await File.WriteAllTextAsync(unrelated, "Preserve unrelated file"); var now = DateTimeOffset.UtcNow; var run = new CvExtractionRun { OwnerUserId = "user-1", ParserVersion = "docling-v1", Trigger = "document_import", Status = status, StartedAtUtc = now.AddDays(-days), RawExtractedText = "Source", DocumentJson = "{}", StructuredProfileJson = "{}", Artifact = new() { OwnerUserId = "user-1", StoragePath = file } }; db.CvExtractionRuns.Add(run); await db.SaveChangesAsync(); await CvImportRetentionHostedService.SweepAsync(db, paths, now, default); Assert.False(File.Exists(orphan)); Assert.True(File.Exists(unrelated)); Assert.Equal(!expires, File.Exists(file)); Assert.Equal(expires, run.DocumentJson is null); Assert.Equal(expires && status == "pending_review" ? "expired" : status, run.Status); } finally { Directory.Delete(root, true); } } }