feat(audit)!: ScadaBridge C3 — swap to canonical ZB.MOM.WW.Audit.AuditEvent across seams/emitters/DTO/redactor wiring; transitional 24-col storage shim (Task 2.5)

This commit is contained in:
Joseph Doherty
2026-06-02 12:37:50 -04:00
parent 5aaf9e2923
commit db707bb0de
127 changed files with 2240 additions and 3886 deletions
@@ -3,7 +3,8 @@ using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using ZB.MOM.WW.ScadaBridge.AuditLog.Site;
using ZB.MOM.WW.ScadaBridge.AuditLog.Tests.TestSupport;
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Audit;
using ZB.MOM.WW.Audit;
using ZB.MOM.WW.ScadaBridge.Commons.Types.Audit;
using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
namespace ZB.MOM.WW.ScadaBridge.AuditLog.Tests.Site;
@@ -237,21 +238,18 @@ public class SqliteAuditWriterSchemaTests
// A WriteAsync binding $ExecutionId must now succeed and round-trip;
// without the ALTER it would fail with "no such column: ExecutionId"
// and — because audit writes are best-effort — silently drop the row.
var evt = new AuditEvent
{
EventId = Guid.NewGuid(),
OccurredAtUtc = DateTime.UtcNow,
Channel = AuditChannel.ApiOutbound,
Kind = AuditKind.ApiCall,
Status = AuditStatus.Delivered,
PayloadTruncated = false,
ExecutionId = executionId,
};
var evt = ScadaBridgeAuditEventFactory.Create(
eventId: Guid.NewGuid(),
occurredAtUtc: DateTime.UtcNow,
channel: AuditChannel.ApiOutbound,
kind: AuditKind.ApiCall,
status: AuditStatus.Delivered,
executionId: executionId);
await writer.WriteAsync(evt);
var rows = await writer.ReadPendingAsync(limit: 10);
var row = Assert.Single(rows);
Assert.Equal(executionId, row.ExecutionId);
Assert.Equal(executionId, row.AsRow().ExecutionId);
}
// Idempotency: a second writer over the now-upgraded DB must not error
@@ -343,23 +341,20 @@ public class SqliteAuditWriterSchemaTests
// round-trip; without the ALTER it would fail with "no such column:
// ParentExecutionId" and — because audit writes are best-effort —
// silently drop the row.
var evt = new AuditEvent
{
EventId = Guid.NewGuid(),
OccurredAtUtc = DateTime.UtcNow,
Channel = AuditChannel.ApiOutbound,
Kind = AuditKind.ApiCall,
Status = AuditStatus.Delivered,
PayloadTruncated = false,
ExecutionId = executionId,
ParentExecutionId = parentExecutionId,
};
var evt = ScadaBridgeAuditEventFactory.Create(
eventId: Guid.NewGuid(),
occurredAtUtc: DateTime.UtcNow,
channel: AuditChannel.ApiOutbound,
kind: AuditKind.ApiCall,
status: AuditStatus.Delivered,
executionId: executionId,
parentExecutionId: parentExecutionId);
await writer.WriteAsync(evt);
var rows = await writer.ReadPendingAsync(limit: 10);
var row = Assert.Single(rows);
Assert.Equal(executionId, row.ExecutionId);
Assert.Equal(parentExecutionId, row.ParentExecutionId);
Assert.Equal(executionId, row.AsRow().ExecutionId);
Assert.Equal(parentExecutionId, row.AsRow().ParentExecutionId);
}
// Idempotency: a second writer over the now-upgraded DB must not error
@@ -376,21 +371,18 @@ public class SqliteAuditWriterSchemaTests
var (writer, _) = CreateWriter(nameof(WriteAsync_NullParentExecutionId_RoundTripsAsNull));
await using (writer)
{
var evt = new AuditEvent
{
EventId = Guid.NewGuid(),
OccurredAtUtc = DateTime.UtcNow,
Channel = AuditChannel.Notification,
Kind = AuditKind.NotifySend,
Status = AuditStatus.Submitted,
PayloadTruncated = false,
// ParentExecutionId left null
};
var evt = ScadaBridgeAuditEventFactory.Create(
eventId: Guid.NewGuid(),
occurredAtUtc: DateTime.UtcNow,
channel: AuditChannel.Notification,
kind: AuditKind.NotifySend,
status: AuditStatus.Submitted);
// ParentExecutionId left null (not a factory arg → defaults null)
await writer.WriteAsync(evt);
var rows = await writer.ReadPendingAsync(limit: 10);
var row = Assert.Single(rows);
Assert.Null(row.ParentExecutionId);
Assert.Null(row.AsRow().ParentExecutionId);
}
}
@@ -473,16 +465,13 @@ public class SqliteAuditWriterSchemaTests
// A WriteAsync binding $SourceNode must now succeed and round-trip;
// without the ALTER it would fail with "no such column: SourceNode"
// and — because audit writes are best-effort — silently drop the row.
var evt = new AuditEvent
{
EventId = Guid.NewGuid(),
OccurredAtUtc = DateTime.UtcNow,
Channel = AuditChannel.ApiOutbound,
Kind = AuditKind.ApiCall,
Status = AuditStatus.Delivered,
PayloadTruncated = false,
SourceNode = "node-a",
};
var evt = ScadaBridgeAuditEventFactory.Create(
eventId: Guid.NewGuid(),
occurredAtUtc: DateTime.UtcNow,
channel: AuditChannel.ApiOutbound,
kind: AuditKind.ApiCall,
status: AuditStatus.Delivered,
sourceNode: "node-a");
await writer.WriteAsync(evt);
var rows = await writer.ReadPendingAsync(limit: 10);
@@ -504,16 +493,13 @@ public class SqliteAuditWriterSchemaTests
var (writer, _) = CreateWriter(nameof(WriteAsync_persists_SourceNode_field));
await using (writer)
{
var evt = new AuditEvent
{
EventId = Guid.NewGuid(),
OccurredAtUtc = DateTime.UtcNow,
Channel = AuditChannel.ApiOutbound,
Kind = AuditKind.ApiCall,
Status = AuditStatus.Delivered,
PayloadTruncated = false,
SourceNode = "node-a",
};
var evt = ScadaBridgeAuditEventFactory.Create(
eventId: Guid.NewGuid(),
occurredAtUtc: DateTime.UtcNow,
channel: AuditChannel.ApiOutbound,
kind: AuditKind.ApiCall,
status: AuditStatus.Delivered,
sourceNode: "node-a");
await writer.WriteAsync(evt);
var rows = await writer.ReadPendingAsync(limit: 10);
@@ -528,16 +514,13 @@ public class SqliteAuditWriterSchemaTests
var (writer, _) = CreateWriter(nameof(WriteAsync_persists_null_SourceNode));
await using (writer)
{
var evt = new AuditEvent
{
EventId = Guid.NewGuid(),
OccurredAtUtc = DateTime.UtcNow,
Channel = AuditChannel.Notification,
Kind = AuditKind.NotifySend,
Status = AuditStatus.Submitted,
PayloadTruncated = false,
// SourceNode left null
};
var evt = ScadaBridgeAuditEventFactory.Create(
eventId: Guid.NewGuid(),
occurredAtUtc: DateTime.UtcNow,
channel: AuditChannel.Notification,
kind: AuditKind.NotifySend,
status: AuditStatus.Submitted);
// SourceNode left null (not a factory arg → defaults null)
await writer.WriteAsync(evt);
var rows = await writer.ReadPendingAsync(limit: 10);