docs+code: close Theme 1 — 24 design-doc / XML-doc drift findings

Doc/XML-comment drift + small adherence fixes across 17 modules. Highlights:
- Host-017: site CoordinatedShutdown ordering — SiteStreamGrpcServer gains
  CancelAllStreams() (refuse new streams, cancel active), wired into
  Program.cs site branch via ApplicationStopping.
- InboundAPI-021: ParentExecutionId now travels on RouteToGet/SetAttributes
  symmetric with RouteToCallRequest; RouteHelper stamps from _parentExecutionId.
- ClusterInfra-012: ClusterOptionsValidator now requires both seed nodes.
- Comm-018: SiteCommunicationActor.HeartbeatMessage.IsActive derived from
  cluster leader check (was hardcoded true).
- DM-020: reconciliation audit row attributes the current user, not prior deployer.
- SEL-019: EventLogPurgeService early-exits on standby via active-node check.
- Plus comment/XML-doc accuracy fixes across AuditLog, ConfigurationDatabase,
  NotificationOutbox, SiteRuntime, SiteCallAudit; doc refreshes for Component-
  Commons / -ManagementService / -CLI / -ExternalSystemGateway / -HealthMonitoring
  / -Transport / -ConfigurationDatabase; CD-023 index-name doc alignment.

11 new regression tests (RouteHelper x4, SiteStreamGrpcServer x2,
ClusterOptionsValidator x1, SiteCommunicationActor x1, DeploymentService x1,
EventLogPurgeService x3). Build clean (0 warnings); InboundAPI/Communication/
Host suites all green. README regenerated: 112 open (was 136).
This commit is contained in:
Joseph Doherty
2026-05-28 06:28:31 -04:00
parent e3ca9af1be
commit 487859bff0
51 changed files with 940 additions and 188 deletions
@@ -2,6 +2,7 @@ using Akka.Actor;
using Akka.Cluster.Tools.Client;
using Akka.TestKit.Xunit2;
using ScadaLink.Commons.Messages.Deployment;
using ScadaLink.Commons.Messages.Health;
using ScadaLink.Commons.Messages.Lifecycle;
using ScadaLink.Commons.Messages.Integration;
using ScadaLink.Commons.Messages.Notification;
@@ -282,4 +283,35 @@ public class SiteCommunicationActorTests : TestKit
Assert.False(ack.Applied);
Assert.NotNull(ack.ErrorMessage);
}
// ── Communication-018: heartbeat IsActive reflects this node's cluster role ──
[Theory]
[InlineData(true)]
[InlineData(false)]
public void Heartbeat_StampsIsActive_FromInjectedCheck(bool isActive)
{
// Communication-018: HeartbeatMessage.IsActive must reflect the actual
// active/standby role of this node, not a hard-coded `true`. The actor
// now takes a Func<bool> override (defaulting to a real Akka.Cluster
// leader check in production); tests inject a stub so they do not need
// to bring up a full cluster in the TestKit ActorSystem.
var dmProbe = CreateTestProbe();
var centralClientProbe = CreateTestProbe();
var fastHeartbeatOptions = new CommunicationOptions
{
TransportHeartbeatInterval = TimeSpan.FromMilliseconds(50)
};
var siteActor = Sys.ActorOf(Props.Create(() =>
new SiteCommunicationActor("site1", fastHeartbeatOptions, dmProbe.Ref, () => isActive)));
siteActor.Tell(new RegisterCentralClient(centralClientProbe.Ref));
var send = centralClientProbe.FishForMessage<ClusterClient.Send>(
s => s.Message is HeartbeatMessage, TimeSpan.FromSeconds(3));
var heartbeat = Assert.IsType<HeartbeatMessage>(send.Message);
Assert.Equal(isActive, heartbeat.IsActive);
Assert.Equal("site1", heartbeat.SiteId);
}
}