feat(auditlog): ParentExecutionId column on AuditEvent + central AuditLog
This commit is contained in:
@@ -74,9 +74,10 @@ public class AuditLogEntityTypeConfigurationTests : IDisposable
|
||||
.Where(p => !p.IsShadowProperty())
|
||||
.ToList();
|
||||
|
||||
// AuditEvent record exposes 22 init-only properties (alog.md §4 plus the
|
||||
// additive ExecutionId universal correlation column).
|
||||
Assert.Equal(22, properties.Count);
|
||||
// AuditEvent record exposes 23 init-only properties (alog.md §4 plus the
|
||||
// additive ExecutionId universal correlation column and its
|
||||
// ParentExecutionId sibling).
|
||||
Assert.Equal(23, properties.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -92,13 +93,15 @@ public class AuditLogEntityTypeConfigurationTests : IDisposable
|
||||
|
||||
// Five reconciliation/query indexes from alog.md §4, plus the EventId unique
|
||||
// index introduced alongside the composite PK (Bundle C), plus the additive
|
||||
// IX_AuditLog_Execution index supporting ExecutionId lookups.
|
||||
// IX_AuditLog_Execution index supporting ExecutionId lookups and the
|
||||
// IX_AuditLog_ParentExecution index supporting ParentExecutionId lookups.
|
||||
var expected = new[]
|
||||
{
|
||||
"IX_AuditLog_Channel_Status_Occurred",
|
||||
"IX_AuditLog_CorrelationId",
|
||||
"IX_AuditLog_Execution",
|
||||
"IX_AuditLog_OccurredAtUtc",
|
||||
"IX_AuditLog_ParentExecution",
|
||||
"IX_AuditLog_Site_Occurred",
|
||||
"IX_AuditLog_Target_Occurred",
|
||||
"UX_AuditLog_EventId",
|
||||
@@ -143,5 +146,9 @@ public class AuditLogEntityTypeConfigurationTests : IDisposable
|
||||
var executionIdx = entity.GetIndexes()
|
||||
.Single(i => i.GetDatabaseName() == "IX_AuditLog_Execution");
|
||||
Assert.Equal("[ExecutionId] IS NOT NULL", executionIdx.GetFilter());
|
||||
|
||||
var parentExecutionIdx = entity.GetIndexes()
|
||||
.Single(i => i.GetDatabaseName() == "IX_AuditLog_ParentExecution");
|
||||
Assert.Equal("[ParentExecutionId] IS NOT NULL", parentExecutionIdx.GetFilter());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,6 +275,35 @@ public class AuditLogRepositoryTests : IClassFixture<MsSqlMigrationFixture>
|
||||
Assert.All(rows, r => Assert.Equal(executionId, r.ExecutionId));
|
||||
}
|
||||
|
||||
[SkippableFact]
|
||||
public async Task QueryAsync_FilterByParentExecutionId_ReturnsMatchingRows()
|
||||
{
|
||||
Skip.IfNot(_fixture.Available, _fixture.SkipReason);
|
||||
|
||||
var siteId = NewSiteId();
|
||||
await using var context = CreateContext();
|
||||
var repo = new AuditLogRepository(context);
|
||||
|
||||
var parentExecutionId = Guid.NewGuid();
|
||||
var t0 = new DateTime(2026, 5, 3, 13, 0, 0, DateTimeKind.Utc);
|
||||
// Two rows share the ParentExecutionId; one carries a different
|
||||
// ParentExecutionId and one leaves it null — both must be excluded by the
|
||||
// single-value filter.
|
||||
await repo.InsertIfNotExistsAsync(NewEvent(siteId, occurredAtUtc: t0, parentExecutionId: parentExecutionId));
|
||||
await repo.InsertIfNotExistsAsync(NewEvent(siteId, occurredAtUtc: t0.AddMinutes(1), parentExecutionId: parentExecutionId));
|
||||
await repo.InsertIfNotExistsAsync(NewEvent(siteId, occurredAtUtc: t0.AddMinutes(2), parentExecutionId: Guid.NewGuid()));
|
||||
await repo.InsertIfNotExistsAsync(NewEvent(siteId, occurredAtUtc: t0.AddMinutes(3), parentExecutionId: null));
|
||||
|
||||
var rows = await repo.QueryAsync(
|
||||
new AuditLogQueryFilter(
|
||||
SourceSiteIds: new[] { siteId },
|
||||
ParentExecutionId: parentExecutionId),
|
||||
new AuditLogPaging(PageSize: 10));
|
||||
|
||||
Assert.Equal(2, rows.Count);
|
||||
Assert.All(rows, r => Assert.Equal(parentExecutionId, r.ParentExecutionId));
|
||||
}
|
||||
|
||||
[SkippableFact]
|
||||
public async Task QueryAsync_FilterByTimeRange()
|
||||
{
|
||||
@@ -754,7 +783,8 @@ public class AuditLogRepositoryTests : IClassFixture<MsSqlMigrationFixture>
|
||||
AuditKind kind = AuditKind.ApiCall,
|
||||
AuditStatus status = AuditStatus.Delivered,
|
||||
string? errorMessage = null,
|
||||
Guid? executionId = null) =>
|
||||
Guid? executionId = null,
|
||||
Guid? parentExecutionId = null) =>
|
||||
new()
|
||||
{
|
||||
EventId = Guid.NewGuid(),
|
||||
@@ -765,5 +795,6 @@ public class AuditLogRepositoryTests : IClassFixture<MsSqlMigrationFixture>
|
||||
SourceSiteId = siteId,
|
||||
ErrorMessage = errorMessage,
|
||||
ExecutionId = executionId,
|
||||
ParentExecutionId = parentExecutionId,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user