From 4f291ed09c660c4c6f6b07bc520d792cab9cbbfa Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Thu, 11 Jun 2026 09:02:02 -0400 Subject: [PATCH] test(redundancy): cover absent-node default-historize for HistorianAdapter (A2) --- .../Historian/HistorianAdapterActorTests.cs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Historian/HistorianAdapterActorTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Historian/HistorianAdapterActorTests.cs index 72115b77..0356fc8e 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Historian/HistorianAdapterActorTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Historian/HistorianAdapterActorTests.cs @@ -135,4 +135,33 @@ public sealed class HistorianAdapterActorTests : RuntimeActorTestBase AwaitAssert(() => sink.EnqueueCount.ShouldBe(1), Settle); } + + /// Absent-node default-historize (T5): a snapshot that mentions only a DIFFERENT node + /// must NOT update the local cached role — the actor's own node is absent, so the role stays + /// null/unknown and the default-historize path must fire. Partial/stale snapshots MUST NOT + /// silently suppress historization for nodes not yet observed. + [Fact] + public void Redundancy_snapshot_without_local_node_leaves_role_unknown_and_historizes() + { + var sink = new RecordingSink(); + var actor = Sys.ActorOf(HistorianAdapterActor.Props(sink, LocalNode)); + + // Send a snapshot that only describes a peer node — the local node is absent. + actor.Tell(new RedundancyStateChanged( + new[] + { + new NodeRedundancyState( + NodeId: new NodeId("some-other-node"), + Role: RedundancyRole.Secondary, + IsClusterLeader: false, + IsRoleLeaderForDriver: false, + AsOfUtc: DateTime.UtcNow), + }, + CorrelationId.NewId())); + + actor.Tell(SampleEvent()); + + // Local role is still unknown ⇒ default-historize path: sink must record exactly one enqueue. + AwaitAssert(() => sink.EnqueueCount.ShouldBe(1), Settle); + } }