using Akka.Actor; using Shouldly; using Xunit; using ZB.MOM.WW.OtOpcUa.Commons.Messages.Redundancy; using ZB.MOM.WW.OtOpcUa.ControlPlane.Redundancy; using ZB.MOM.WW.OtOpcUa.ControlPlane.Tests.Harness; namespace ZB.MOM.WW.OtOpcUa.ControlPlane.Tests; /// /// Verifies publishes a /// snapshot in response to cluster events, and that the 250ms debounce coalesces bursts. /// The actor accepts an Action<object> broadcast override so tests can use a /// TestProbe sink instead of bootstrapping DistributedPubSub (which is flaky single-node). /// public sealed class RedundancyStateActorTests : ControlPlaneActorTestBase { [Fact] public void Self_join_triggers_RedundancyStateChanged_via_broadcast_override() { var probe = CreateTestProbe("redundancy-listener"); Sys.ActorOf(RedundancyStateActor.Props(broadcast: msg => probe.Ref.Tell(msg)), "redundancy-actor"); var msg = probe.ExpectMsg(TimeSpan.FromSeconds(3)); msg.Nodes.ShouldNotBeNull(); msg.CorrelationId.Value.ShouldNotBe(Guid.Empty); } [Fact] public void Multiple_back_to_back_events_debounce_to_single_publish() { var probe = CreateTestProbe("dedup-listener"); Sys.ActorOf(RedundancyStateActor.Props(broadcast: msg => probe.Ref.Tell(msg)), "redundancy-debounce"); // First publish should arrive within the debounce window. probe.ExpectMsg(TimeSpan.FromSeconds(3)); // After debounce settles, no more events are fired by a quiescent cluster. probe.ExpectNoMsg(TimeSpan.FromMilliseconds(500)); } }