diff --git a/src/ZB.MOM.WW.ScadaBridge.DataConnectionLayer/Actors/DataConnectionManagerActor.cs b/src/ZB.MOM.WW.ScadaBridge.DataConnectionLayer/Actors/DataConnectionManagerActor.cs index 1bab2494..5069c1b1 100644 --- a/src/ZB.MOM.WW.ScadaBridge.DataConnectionLayer/Actors/DataConnectionManagerActor.cs +++ b/src/ZB.MOM.WW.ScadaBridge.DataConnectionLayer/Actors/DataConnectionManagerActor.cs @@ -43,6 +43,8 @@ public class DataConnectionManagerActor : ReceiveActor Receive(HandleCreateConnection); Receive(HandleRoute); Receive(HandleRoute); + Receive(HandleRouteAlarms); + Receive(HandleRouteAlarms); Receive(HandleRouteWrite); Receive(HandleRemoveConnection); Receive(HandleGetAllHealthReports); @@ -101,6 +103,31 @@ public class DataConnectionManagerActor : ReceiveActor _log.Warning("No connection actor for {0} during unsubscribe", request.ConnectionName); } + /// + /// Routes a native alarm subscribe to the that owns + /// the named connection (the NativeAlarmActor sends here, not to the child directly). + /// + private void HandleRouteAlarms(SubscribeAlarmsRequest request) + { + if (_connectionActors.TryGetValue(request.ConnectionName, out var actor)) + actor.Forward(request); + else + { + _log.Warning("No connection actor for {0} during alarm subscribe", request.ConnectionName); + Sender.Tell(new SubscribeAlarmsResponse( + request.CorrelationId, request.InstanceUniqueName, false, + $"Unknown connection: {request.ConnectionName}", DateTimeOffset.UtcNow)); + } + } + + private void HandleRouteAlarms(UnsubscribeAlarmsRequest request) + { + if (_connectionActors.TryGetValue(request.ConnectionName, out var actor)) + actor.Forward(request); + else + _log.Warning("No connection actor for {0} during alarm unsubscribe", request.ConnectionName); + } + private void HandleRouteWrite(WriteTagRequest request) { if (_connectionActors.TryGetValue(request.ConnectionName, out var actor)) diff --git a/tests/ZB.MOM.WW.ScadaBridge.DataConnectionLayer.Tests/DataConnectionManagerActorTests.cs b/tests/ZB.MOM.WW.ScadaBridge.DataConnectionLayer.Tests/DataConnectionManagerActorTests.cs index fa143dd9..77a47908 100644 --- a/tests/ZB.MOM.WW.ScadaBridge.DataConnectionLayer.Tests/DataConnectionManagerActorTests.cs +++ b/tests/ZB.MOM.WW.ScadaBridge.DataConnectionLayer.Tests/DataConnectionManagerActorTests.cs @@ -58,6 +58,23 @@ public class DataConnectionManagerActorTests : TestKit Assert.Contains("Unknown connection", response.ErrorMessage); } + [Fact] + public void SubscribeAlarmsToUnknownConnection_ReturnsError() + { + // Regression for the live integration gap: the NativeAlarmActor sends + // SubscribeAlarmsRequest to the DCL manager, which must route it to the + // named connection actor (or reply with an error) — not dead-letter it. + var manager = Sys.ActorOf(Props.Create(() => + new DataConnectionManagerActor(_mockFactory, _options, _mockHealthCollector))); + + manager.Tell(new SubscribeAlarmsRequest( + "corr1", "inst1", "nonexistent", "ns=2;s=Tank01", null, DateTimeOffset.UtcNow)); + + var response = ExpectMsg(); + Assert.False(response.Success); + Assert.Contains("Unknown connection", response.ErrorMessage); + } + [Fact] public async Task DCL002_ConnectionActorCrash_PreservesSubscriptionState() {