2b19bddf7b
CI / backend (push) Successful in 52s
CI / frontend (push) Successful in 11s
Deploy Staging / deploy (push) Successful in 24s
Security / secrets (push) Successful in 4s
Security / dependencies (push) Successful in 52s
CI / backend (pull_request) Successful in 49s
CI / frontend (pull_request) Successful in 10s
Security / secrets (pull_request) Successful in 3s
Security / dependencies (pull_request) Successful in 55s
74 lines
2.9 KiB
C#
74 lines
2.9 KiB
C#
using FluentAssertions;
|
|
using InboxIntel.Application.Abstractions;
|
|
using InboxIntel.Domain.Entities;
|
|
using InboxIntel.Infrastructure.Configuration;
|
|
using InboxIntel.Infrastructure.Persistence;
|
|
using InboxIntel.Infrastructure.Retention;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.Logging.Abstractions;
|
|
using Microsoft.Extensions.Options;
|
|
using Xunit;
|
|
|
|
namespace InboxIntel.IntegrationTests;
|
|
|
|
/// <summary>
|
|
/// AUDIT H-3 (retention): the purge removes only what the configuration targets and is a
|
|
/// no-op while disabled — locking the "no behaviour change until opted in" guarantee.
|
|
/// </summary>
|
|
public class RetentionServiceTests
|
|
{
|
|
private sealed class FakeCurrentUser : ICurrentUser
|
|
{
|
|
public Guid UserId => Guid.Empty; // worker scope
|
|
public bool IsAuthenticated => false;
|
|
}
|
|
|
|
private static AppDbContext NewDb(string name) =>
|
|
new(new DbContextOptionsBuilder<AppDbContext>().UseInMemoryDatabase(name).Options, new FakeCurrentUser());
|
|
|
|
private static async Task SeedAsync(AppDbContext db)
|
|
{
|
|
var user = Guid.NewGuid();
|
|
db.Emails.AddRange(
|
|
new Email { UserId = user, GmailMessageId = "old-trashed", IsTrashed = true, SentAtUtc = DateTimeOffset.UtcNow.AddDays(-100) },
|
|
new Email { UserId = user, GmailMessageId = "new-trashed", IsTrashed = true, SentAtUtc = DateTimeOffset.UtcNow.AddDays(-5) },
|
|
new Email { UserId = user, GmailMessageId = "old-kept", IsTrashed = false, SentAtUtc = DateTimeOffset.UtcNow.AddDays(-100) });
|
|
await db.SaveChangesAsync();
|
|
}
|
|
|
|
private static RetentionService Sut(AppDbContext db, int trashedDays = 0, int allDays = 0) =>
|
|
new(db, Options.Create(new DataRetentionOptions
|
|
{
|
|
PurgeTrashedAfterDays = trashedDays,
|
|
PurgeAllAfterDays = allDays
|
|
}), NullLogger<RetentionService>.Instance);
|
|
|
|
[Fact]
|
|
public async Task Disabled_retention_purges_nothing()
|
|
{
|
|
using var db = NewDb(nameof(Disabled_retention_purges_nothing));
|
|
await SeedAsync(db);
|
|
(await Sut(db).PurgeAsync()).Should().Be(0);
|
|
(await db.Emails.CountAsync()).Should().Be(3);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Trashed_purge_removes_only_old_trashed_emails()
|
|
{
|
|
using var db = NewDb(nameof(Trashed_purge_removes_only_old_trashed_emails));
|
|
await SeedAsync(db);
|
|
(await Sut(db, trashedDays: 30).PurgeAsync()).Should().Be(1);
|
|
var remaining = await db.Emails.Select(e => e.GmailMessageId).ToListAsync();
|
|
remaining.Should().BeEquivalentTo(new[] { "new-trashed", "old-kept" });
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Age_purge_removes_everything_past_the_cutoff()
|
|
{
|
|
using var db = NewDb(nameof(Age_purge_removes_everything_past_the_cutoff));
|
|
await SeedAsync(db);
|
|
(await Sut(db, allDays: 30).PurgeAsync()).Should().Be(2); // both 100-day-old emails
|
|
(await db.Emails.SingleAsync()).GmailMessageId.Should().Be("new-trashed");
|
|
}
|
|
}
|