using Akka.Actor; using Akka.Cluster.Tools.Client; using Akka.TestKit.Xunit2; using ZB.MOM.WW.ScadaBridge.Commons.Messages.Notification; using ZB.MOM.WW.ScadaBridge.Communication.Actors; namespace ZB.MOM.WW.ScadaBridge.Communication.Tests.Actors; /// /// T1A.3: the regression-prone bit of the Akka transport — that a forwarded /// carries the caller's sender, so central's reply routes /// straight back to the waiting Ask rather than to the site communication actor — plus the /// no-ClusterClient-yet fallback that keeps the S&F layer treating the send as transient. /// public class AkkaCentralTransportTests : TestKit { [Fact] public void SubmitNotification_ForwardsToClusterClient_WithReplyToAsSender() { var transport = new AkkaCentralTransport(); var clusterClient = CreateTestProbe(); var replyTo = CreateTestProbe(); transport.SetCentralClient(clusterClient.Ref); var submit = new NotificationSubmit( "notif-1", "Operators", "S", "B", "site1", null, null, DateTimeOffset.UtcNow); transport.SubmitNotification(submit, replyTo.Ref); // The ClusterClient receives a Send addressed to the central actor... var send = clusterClient.ExpectMsg(); Assert.Equal("/user/central-communication", send.Path); Assert.IsType(send.Message); // ...and replying to it lands at replyTo, proving the sender was forwarded (not the // transport / actor). This is the routing the waiting Ask relies on. clusterClient.Reply(new NotificationSubmitAck("notif-1", Accepted: true, Error: null)); replyTo.ExpectMsg(ack => ack.NotificationId == "notif-1" && ack.Accepted); } [Fact] public void SubmitNotification_WithNoClusterClient_RepliesNonAcceptedToReplyTo() { var transport = new AkkaCentralTransport(); var replyTo = CreateTestProbe(); transport.SubmitNotification( new NotificationSubmit("notif-2", "Operators", "S", "B", "site1", null, null, DateTimeOffset.UtcNow), replyTo.Ref); replyTo.ExpectMsg(ack => ack.NotificationId == "notif-2" && !ack.Accepted); } [Fact] public void IngestAuditEvents_WithNoClusterClient_FaultsTheReplyTo() { // The audit drain treats a faulted Ask as transient and keeps rows Pending — so the // no-client path must be a Status.Failure, not a silent drop. var transport = new AkkaCentralTransport(); var replyTo = CreateTestProbe(); transport.IngestAuditEvents( new Commons.Messages.Audit.IngestAuditEventsCommand(new List()), replyTo.Ref); replyTo.ExpectMsg(); } }