using Akka.Actor; using Akka.TestKit.Xunit2; using NSubstitute; using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Protocol; using ZB.MOM.WW.ScadaBridge.Commons.Messages.DataConnection; using ZB.MOM.WW.ScadaBridge.Commons.Types.Alarms; using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums; using ZB.MOM.WW.ScadaBridge.DataConnectionLayer.Actors; using ZB.MOM.WW.ScadaBridge.HealthMonitoring; namespace ZB.MOM.WW.ScadaBridge.DataConnectionLayer.Tests; /// Task-10: native alarm subscribe + source-ref routing + unavailable signal. public class DataConnectionActorAlarmTests : TestKit { private readonly ISiteHealthCollector _health = Substitute.For(); private readonly IDataConnectionFactory _factory = Substitute.For(); private readonly DataConnectionOptions _options = new() { ReconnectInterval = TimeSpan.FromMilliseconds(100), TagResolutionRetryInterval = TimeSpan.FromMilliseconds(200), WriteTimeout = TimeSpan.FromSeconds(5) }; private static NativeAlarmTransition Raise(string sourceRef, string sourceObj) => new(sourceRef, sourceObj, "AnalogLimit.Hi", AlarmTransitionKind.Raise, new AlarmConditionState(true, false, null, AlarmShelveState.Unshelved, false, 500), "Process", "hi", "hi", "", "", null, DateTimeOffset.UtcNow, "92", "90"); [Fact] public void SubscribeAlarms_RoutesTransitionToInstanceSubscriber() { AlarmTransitionCallback? cb = null; var adapter = Substitute.For(); adapter.ConnectAsync(Arg.Any>(), Arg.Any()) .Returns(Task.CompletedTask); ((IAlarmSubscribableConnection)adapter) .SubscribeAlarmsAsync(Arg.Any(), Arg.Any(), Arg.Do(c => cb = c), Arg.Any()) .Returns(Task.FromResult("alarm-sub-1")); var actor = Sys.ActorOf(Props.Create(() => new DataConnectionActor( "conn", adapter, _options, _health, _factory, "OpcUa"))); actor.Tell(new SubscribeAlarmsRequest("c", "inst", "conn", "Tank01", null, DateTimeOffset.UtcNow)); ExpectMsg(m => m.Success); Assert.NotNull(cb); cb!(Raise("Tank01.Hi", "Tank01")); ExpectMsg(u => u.Transition.SourceObjectReference == "Tank01"); } [Fact] public void SubscribeAlarms_OnNonAlarmCapableAdapter_RepliesFailure() { var adapter = Substitute.For(); // not IAlarmSubscribableConnection adapter.ConnectAsync(Arg.Any>(), Arg.Any()) .Returns(Task.CompletedTask); var actor = Sys.ActorOf(Props.Create(() => new DataConnectionActor( "conn", adapter, _options, _health, _factory, "OpcUa"))); actor.Tell(new SubscribeAlarmsRequest("c", "inst", "conn", "Tank01", null, DateTimeOffset.UtcNow)); ExpectMsg(m => !m.Success && m.ErrorMessage != null); } }