Files
ScadaBridge/tests/ZB.MOM.WW.ScadaBridge.Communication.Tests/Protos/CachedTelemetryProtoTests.cs
T
Joseph Doherty 513fa1aa16 docs(tests): fix CommentChecker findings across tests/ — 13,392 → 0 (repo-wide scan clean)
Comment/XML-doc changes only:
- add summaries to ~10k test methods, fixtures, fakes and helpers
  (+ <param> on theories, <returns> on async Task methods,
  <inheritdoc/> on interface implementations the checker can resolve)
- strip ~2.6k project-tracking references (WP*, P*-*, row-NN, Task N,
  #NN, Component-0NN) from comments, keeping the explanatory text;
  reword false positives in comments only
- real docs on fakes implementing BCL/library interfaces
  (IDisposable, ILogger, IOptionsMonitor, IAsyncLifetime)
- reword the last 5 src/ false positives (CWE-1236, failures-1,
  year-0001, M365)

Only non-comment edits: four one-line nested classes split across lines
so members can carry docs. Build 0 errors / 0 warnings.
2026-10-07 15:05:49 -04:00

181 lines
7.3 KiB
C#

using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ZB.MOM.WW.ScadaBridge.Communication.Grpc;
namespace ZB.MOM.WW.ScadaBridge.Communication.Tests.Protos;
/// <summary>
/// Wire-format round-trip tests for the Audit Log cached-telemetry
/// proto messages (<see cref="SiteCallOperationalDto"/>,
/// <see cref="CachedTelemetryPacket"/>, <see cref="CachedTelemetryBatch"/>).
/// Locks the additive contract the central dual-write transaction depends on.
/// </summary>
public class CachedTelemetryProtoTests
{
private static AuditEventDto NewAuditDto(Guid? id = null) => new()
{
EventId = (id ?? Guid.NewGuid()).ToString(),
OccurredAtUtc = Timestamp.FromDateTimeOffset(
new DateTimeOffset(2026, 5, 20, 10, 15, 30, 123, TimeSpan.Zero)),
Channel = "ApiOutbound",
Kind = "CachedSubmit",
Status = "Submitted",
SourceSiteId = "site-1",
};
/// <summary>Verifies that a <c>SiteCallOperationalDto</c> round trip preserves all fields.</summary>
[Fact]
public void SiteCallOperationalDto_RoundTrip_PreservesAllFields()
{
var createdAt = Timestamp.FromDateTimeOffset(
new DateTimeOffset(2026, 5, 20, 10, 0, 0, TimeSpan.Zero));
var updatedAt = Timestamp.FromDateTimeOffset(
new DateTimeOffset(2026, 5, 20, 10, 5, 0, TimeSpan.Zero));
var terminalAt = Timestamp.FromDateTimeOffset(
new DateTimeOffset(2026, 5, 20, 10, 10, 0, TimeSpan.Zero));
var original = new SiteCallOperationalDto
{
TrackedOperationId = Guid.NewGuid().ToString(),
Channel = "ApiOutbound",
Target = "ERP.GetOrder",
SourceSite = "site-melbourne",
SourceNode = "node-a",
Status = "Delivered",
RetryCount = 3,
LastError = "transient 503",
HttpStatus = 200,
CreatedAtUtc = createdAt,
UpdatedAtUtc = updatedAt,
TerminalAtUtc = terminalAt,
};
var bytes = original.ToByteArray();
var deserialized = SiteCallOperationalDto.Parser.ParseFrom(bytes);
Assert.Equal(original.TrackedOperationId, deserialized.TrackedOperationId);
Assert.Equal(original.Channel, deserialized.Channel);
Assert.Equal(original.Target, deserialized.Target);
Assert.Equal(original.SourceSite, deserialized.SourceSite);
Assert.Equal(original.SourceNode, deserialized.SourceNode);
Assert.Equal(original.Status, deserialized.Status);
Assert.Equal(original.RetryCount, deserialized.RetryCount);
Assert.Equal(original.LastError, deserialized.LastError);
Assert.Equal(original.HttpStatus, deserialized.HttpStatus);
Assert.Equal(original.CreatedAtUtc, deserialized.CreatedAtUtc);
Assert.Equal(original.UpdatedAtUtc, deserialized.UpdatedAtUtc);
Assert.Equal(original.TerminalAtUtc, deserialized.TerminalAtUtc);
}
/// <summary>Verifies that the terminal timestamp is absent when the call is not terminal.</summary>
[Fact]
public void SiteCallOperationalDto_TerminalAt_AbsentWhenNotTerminal()
{
// Lifecycle events prior to the terminal step leave TerminalAtUtc unset;
// the well-known Timestamp wrapper is absent on the wire (null in C#).
var dto = new SiteCallOperationalDto
{
TrackedOperationId = Guid.NewGuid().ToString(),
Channel = "DbOutbound",
Target = "warehouse.dbo.WriteOrder",
SourceSite = "site-brisbane",
Status = "Attempted",
RetryCount = 1,
CreatedAtUtc = Timestamp.FromDateTimeOffset(DateTimeOffset.UtcNow),
UpdatedAtUtc = Timestamp.FromDateTimeOffset(DateTimeOffset.UtcNow),
};
Assert.Null(dto.TerminalAtUtc);
var bytes = dto.ToByteArray();
var deserialized = SiteCallOperationalDto.Parser.ParseFrom(bytes);
Assert.Null(deserialized.TerminalAtUtc);
}
/// <summary>Verifies that the nullable HTTP status is absent by default.</summary>
[Fact]
public void SiteCallOperationalDto_NullableHttpStatus_AbsentByDefault()
{
// Int32Value wrapper-typed http_status — unset round-trips as null,
// matching DB nullable column semantics for non-API cached writes.
var dto = new SiteCallOperationalDto
{
TrackedOperationId = Guid.NewGuid().ToString(),
Channel = "DbOutbound",
Target = "warehouse.dbo.WriteOrder",
SourceSite = "site-brisbane",
Status = "Submitted",
RetryCount = 0,
CreatedAtUtc = Timestamp.FromDateTimeOffset(DateTimeOffset.UtcNow),
UpdatedAtUtc = Timestamp.FromDateTimeOffset(DateTimeOffset.UtcNow),
};
Assert.Null(dto.HttpStatus);
var bytes = dto.ToByteArray();
var deserialized = SiteCallOperationalDto.Parser.ParseFrom(bytes);
Assert.Null(deserialized.HttpStatus);
}
/// <summary>Verifies that a <c>CachedTelemetryPacket</c> round trip preserves its nested entities.</summary>
[Fact]
public void CachedTelemetryPacket_RoundTrip_PreservesNestedEntities()
{
var trackedOpId = Guid.NewGuid().ToString();
var auditDto = NewAuditDto();
auditDto.Target = "ERP.GetOrder";
auditDto.Status = "Attempted";
var operationalDto = new SiteCallOperationalDto
{
TrackedOperationId = trackedOpId,
Channel = "ApiOutbound",
Target = "ERP.GetOrder",
SourceSite = "site-1",
Status = "Attempted",
RetryCount = 2,
HttpStatus = 503,
LastError = "Service unavailable",
CreatedAtUtc = Timestamp.FromDateTimeOffset(DateTimeOffset.UtcNow),
UpdatedAtUtc = Timestamp.FromDateTimeOffset(DateTimeOffset.UtcNow),
};
var original = new CachedTelemetryPacket
{
AuditEvent = auditDto,
Operational = operationalDto,
};
var bytes = original.ToByteArray();
var deserialized = CachedTelemetryPacket.Parser.ParseFrom(bytes);
Assert.NotNull(deserialized.AuditEvent);
Assert.Equal(auditDto.EventId, deserialized.AuditEvent.EventId);
Assert.Equal(auditDto.Target, deserialized.AuditEvent.Target);
Assert.Equal(auditDto.Status, deserialized.AuditEvent.Status);
Assert.NotNull(deserialized.Operational);
Assert.Equal(trackedOpId, deserialized.Operational.TrackedOperationId);
Assert.Equal(operationalDto.Channel, deserialized.Operational.Channel);
Assert.Equal(operationalDto.Status, deserialized.Operational.Status);
Assert.Equal(operationalDto.RetryCount, deserialized.Operational.RetryCount);
Assert.Equal(operationalDto.HttpStatus, deserialized.Operational.HttpStatus);
Assert.Equal(operationalDto.LastError, deserialized.Operational.LastError);
}
/// <summary>Verifies that an empty <c>CachedTelemetryBatch</c> round trip yields no packets.</summary>
[Fact]
public void CachedTelemetryBatch_Empty_RoundTrip_Yields_EmptyPackets()
{
var original = new CachedTelemetryBatch();
Assert.Empty(original.Packets);
var bytes = original.ToByteArray();
var deserialized = CachedTelemetryBatch.Parser.ParseFrom(bytes);
Assert.Empty(deserialized.Packets);
}
}