feat(sitecall-audit): add SourceNode to SiteCallOperational + SiteCall entity

This commit is contained in:
Joseph Doherty
2026-05-23 15:53:44 -04:00
parent 354f8792bf
commit 990eb02fe0
10 changed files with 123 additions and 0 deletions

View File

@@ -0,0 +1,40 @@
using ScadaLink.Commons.Entities.Audit;
using ScadaLink.Commons.Types;
namespace ScadaLink.Commons.Tests.Entities.Audit;
/// <summary>
/// Verifies the <see cref="SiteCall"/> central operational entity carries the
/// SourceNode column (additive, nullable) through init-only construction and
/// <c>with</c> expressions. Sibling to <see cref="AuditEventTests"/>.
/// </summary>
public class SiteCallTests
{
private static SiteCall MinimalRow() => new()
{
TrackedOperationId = TrackedOperationId.New(),
Channel = "ApiOutbound",
Target = "ERP.GetOrder",
SourceSite = "site-01",
Status = "Submitted",
RetryCount = 0,
CreatedAtUtc = new DateTime(2026, 5, 23, 12, 0, 0, DateTimeKind.Utc),
UpdatedAtUtc = new DateTime(2026, 5, 23, 12, 0, 0, DateTimeKind.Utc),
IngestedAtUtc = new DateTime(2026, 5, 23, 12, 0, 1, DateTimeKind.Utc),
};
[Fact]
public void SiteCall_carries_SourceNode()
{
// SourceNode identifies the cluster node that emitted the cached call
// (site node-a/node-b or central-a/central-b). Additive nullable init
// property — defaults to null on rows ingested before the column
// existed, and round-trips its value via `with` expressions.
var row = MinimalRow();
Assert.Null(row.SourceNode);
var stamped = row with { SourceNode = "node-b" };
Assert.Equal("node-b", stamped.SourceNode);
Assert.Null(row.SourceNode);
}
}

View File

@@ -60,6 +60,10 @@ public class CachedCallTelemetryTests
Channel: nameof(AuditChannel.ApiOutbound),
Target: "ERP.GetOrder",
SourceSite: SiteId,
// SourceNode: actual stamping arrives with Task 14; for now the
// packet builder leaves the column null so existing assertions on
// the packet's other fields stay intact.
SourceNode: null,
Status: status.ToString(),
RetryCount: retryCount,
LastError: lastError,

View File

@@ -0,0 +1,42 @@
using ScadaLink.Commons.Types;
namespace ScadaLink.Commons.Tests.Types;
/// <summary>
/// Verifies <see cref="SiteCallOperational"/> — the positional record carried on
/// the combined <c>CachedCallTelemetry</c> packet — round-trips the SourceNode
/// field through positional construction (where the parameter sits between
/// <c>SourceSite</c> and <c>Status</c>, mirroring the central <c>SiteCalls</c>
/// table column order).
/// </summary>
public class SiteCallOperationalTests
{
[Fact]
public void SiteCallOperational_carries_SourceNode()
{
// SourceNode identifies the cluster node that emitted the cached call
// (site node-a/node-b or central-a/central-b). Nullable — callsites
// pass null until INodeIdentityProvider stamping arrives in Task 14.
var trackedId = TrackedOperationId.New();
var nowUtc = new DateTime(2026, 5, 23, 12, 0, 0, DateTimeKind.Utc);
var defaulted = new SiteCallOperational(
TrackedOperationId: trackedId,
Channel: "ApiOutbound",
Target: "ERP.GetOrder",
SourceSite: "site-01",
SourceNode: null,
Status: "Submitted",
RetryCount: 0,
LastError: null,
HttpStatus: null,
CreatedAtUtc: nowUtc,
UpdatedAtUtc: nowUtc,
TerminalAtUtc: null);
Assert.Null(defaulted.SourceNode);
var stamped = defaulted with { SourceNode = "node-a" };
Assert.Equal("node-a", stamped.SourceNode);
Assert.Null(defaulted.SourceNode);
}
}