diff --git a/src/ScadaLink.StoreAndForward/NotificationForwarder.cs b/src/ScadaLink.StoreAndForward/NotificationForwarder.cs index 81bb4d5..19bc720 100644 --- a/src/ScadaLink.StoreAndForward/NotificationForwarder.cs +++ b/src/ScadaLink.StoreAndForward/NotificationForwarder.cs @@ -115,7 +115,10 @@ public sealed class NotificationForwarder submit = new NotificationSubmit( NotificationId: message.Id, - ListName: payload.ListName ?? message.Target, + // A null OR empty/blank ListName falls back to the S&F Target — matching the + // empty-string guard the former SMTP handler (NotificationDeliveryService) + // applied, so an empty list name is never forwarded to central. + ListName: string.IsNullOrEmpty(payload.ListName) ? message.Target : payload.ListName, Subject: payload.Subject ?? string.Empty, Body: payload.Message ?? string.Empty, SourceSiteId: _sourceSiteId, diff --git a/tests/ScadaLink.StoreAndForward.Tests/NotificationForwarderTests.cs b/tests/ScadaLink.StoreAndForward.Tests/NotificationForwarderTests.cs index 832f835..1eec959 100644 --- a/tests/ScadaLink.StoreAndForward.Tests/NotificationForwarderTests.cs +++ b/tests/ScadaLink.StoreAndForward.Tests/NotificationForwarderTests.cs @@ -67,6 +67,39 @@ public class NotificationForwarderTests : TestKit Assert.True(await deliverTask); } + [Fact] + public async Task Deliver_FallsBackToTarget_WhenPayloadListNameIsEmpty() + { + var centralProbe = CreateTestProbe(); + var forwarder = new NotificationForwarder( + centralProbe.Ref, "site-7", ForwardTimeout); + + // A buffered payload carrying an empty-string ListName: the empty value must not + // be forwarded — the forwarder falls back to the S&F message Target instead. + var payload = JsonSerializer.Serialize(new + { + ListName = "", + Subject = "Pump alarm", + Message = "Pump 3 tripped" + }); + var msg = new StoreAndForwardMessage + { + Id = "msg-empty-list", + Category = StoreAndForwardCategory.Notification, + Target = "Operators", + PayloadJson = payload, + OriginInstanceName = "Plant.Pump3", + }; + + var deliverTask = forwarder.DeliverAsync(msg); + + var submit = centralProbe.ExpectMsg(); + Assert.Equal("Operators", submit.ListName); + centralProbe.Reply(new NotificationSubmitAck(submit.NotificationId, Accepted: true, Error: null)); + + Assert.True(await deliverTask); + } + [Fact] public async Task Deliver_ThrowsTransient_WhenAckIsNotAccepted() {