Files
tiku-backend.net/Tiku.IntegrationTests/SystemScopeAuditTests.cs

86 lines
4.0 KiB
C#

using Microsoft.Extensions.DependencyInjection;
using Tiku.Application.Security;
using Tiku.Domain.Tenancy;
using Tiku.Infrastructure.Persistence;
namespace Tiku.IntegrationTests;
public sealed class SystemScopeAuditTests
{
[Fact]
public async Task Descriptor_is_required_and_success_is_audited()
{
await using var factory = new Api.ApiTestFactory();
using var outer = factory.CreateSystemScope("Resolve execution scope");
var executionScope = outer.ServiceProvider.GetRequiredService<ITenantExecutionScope>();
await Assert.ThrowsAsync<ArgumentException>(() => executionScope.ExecuteAsync(
new SystemScopeRequest(null, SystemScopeCallerType.Worker, "worker", "", "job-1"),
(_, _) => Task.CompletedTask));
await Assert.ThrowsAsync<ArgumentException>(() => executionScope.ExecuteAsync(
new SystemScopeRequest(null, SystemScopeCallerType.Worker, "worker", "missing target", "job-2"),
(_, _) => Task.CompletedTask));
var correlationId = Guid.NewGuid().ToString("N");
var tenantId = Guid.NewGuid();
await factory.SeedAsync(new Tenant
{
Id = tenantId,
Slug = tenantId.ToString("N"),
Name = "System Scope Tenant"
});
await executionScope.ExecuteAsync(
new SystemScopeRequest(tenantId, SystemScopeCallerType.Worker, "background-worker", "test audit", correlationId),
(_, _) => Task.CompletedTask);
using var verification = factory.CreateSystemScope("Verify execution scope audit");
var dbContext = verification.ServiceProvider.GetRequiredService<TikuDbContext>();
Assert.Contains(dbContext.AuditLogs, item => item.Action == "system_scope.entered" && item.TargetId == correlationId);
Assert.Contains(dbContext.AuditLogs, item => item.Action == "system_scope.completed" && item.TargetId == correlationId);
}
[Fact]
public async Task Failed_system_scope_rolls_back_business_write_and_persists_failure_audit()
{
await using var factory = new Api.ApiTestFactory();
using var outer = factory.CreateSystemScope("Resolve execution scope");
var executionScope = outer.ServiceProvider.GetRequiredService<ITenantExecutionScope>();
var correlationId = Guid.NewGuid().ToString("N");
var tenantId = Guid.NewGuid();
await factory.SeedAsync(new Tenant
{
Id = tenantId,
Slug = tenantId.ToString("N"),
Name = "Existing Tenant"
});
await Assert.ThrowsAsync<InvalidOperationException>(() => executionScope.ExecuteAsync(
new SystemScopeRequest(
tenantId,
SystemScopeCallerType.Worker,
"background-worker",
"verify transactional rollback",
correlationId),
async (provider, cancellationToken) =>
{
var dbContext = provider.GetRequiredService<TikuDbContext>();
dbContext.TenantBrandings.Add(new TenantBranding
{
TenantId = tenantId,
BrandName = "Must Roll Back"
});
await dbContext.SaveChangesAsync(cancellationToken);
throw new InvalidOperationException("expected failure");
}));
using var verification = factory.CreateSystemScope("Verify failed execution scope audit");
var verificationDb = verification.ServiceProvider.GetRequiredService<TikuDbContext>();
Assert.DoesNotContain(verificationDb.TenantBrandings, item => item.TenantId == tenantId);
Assert.Contains(verificationDb.AuditLogs, item =>
item.Action == "system_scope.entered" && item.TargetId == correlationId);
Assert.Contains(verificationDb.AuditLogs, item =>
item.Action == "system_scope.failed" && item.TargetId == correlationId);
Assert.DoesNotContain(verificationDb.AuditLogs, item =>
item.Action == "system_scope.completed" && item.TargetId == correlationId);
}
}