using Microsoft.Extensions.Options; namespace ZB.MOM.WW.ScadaBridge.NotificationOutbox.Tests; /// /// P5-5 (arch-review Low): had no /// registered validator before this — the dispatch/purge/KPI cadences and the /// delivered-throughput KPI window () /// could be zero/negative with no boot-time signal, which would spin an Akka /// scheduler or — because NotificationOutboxKpiSampleSource divides by /// DeliveredKpiWindow to rescale onto KpiHistoryOptions.SampleInterval /// — divide by zero. /// is validated on its BASE property, not the clamped /// , so a /// misconfigured non-positive value fails fast instead of silently clamping to 1. /// public class NotificationOutboxOptionsValidatorTests { private static ValidateOptionsResult Validate(NotificationOutboxOptions options) => new NotificationOutboxOptionsValidator().Validate(Options.DefaultName, options); [Fact] public void DefaultOptions_AreValid() { var result = Validate(new NotificationOutboxOptions()); Assert.True(result.Succeeded, result.FailureMessage); } [Fact] public void ZeroDispatchInterval_IsRejected() { var result = Validate(new NotificationOutboxOptions { DispatchInterval = TimeSpan.Zero }); Assert.True(result.Failed); Assert.Contains("DispatchInterval", result.FailureMessage); } [Fact] public void ZeroDispatchBatchSize_IsRejected() { var result = Validate(new NotificationOutboxOptions { DispatchBatchSize = 0 }); Assert.True(result.Failed); Assert.Contains("DispatchBatchSize", result.FailureMessage); } [Fact] public void ZeroStuckAgeThreshold_IsRejected() { var result = Validate(new NotificationOutboxOptions { StuckAgeThreshold = TimeSpan.Zero }); Assert.True(result.Failed); Assert.Contains("StuckAgeThreshold", result.FailureMessage); } [Fact] public void ZeroTerminalRetention_IsRejected() { var result = Validate(new NotificationOutboxOptions { TerminalRetention = TimeSpan.Zero }); Assert.True(result.Failed); Assert.Contains("TerminalRetention", result.FailureMessage); } [Fact] public void ZeroPurgeInterval_IsRejected() { var result = Validate(new NotificationOutboxOptions { PurgeInterval = TimeSpan.Zero }); Assert.True(result.Failed); Assert.Contains("PurgeInterval", result.FailureMessage); } [Fact] public void ZeroDeliveredKpiWindow_IsRejected() { var result = Validate(new NotificationOutboxOptions { DeliveredKpiWindow = TimeSpan.Zero }); Assert.True(result.Failed); Assert.Contains("DeliveredKpiWindow", result.FailureMessage); } [Fact] public void NegativeDeliveredKpiWindow_IsRejected() { var result = Validate(new NotificationOutboxOptions { DeliveredKpiWindow = TimeSpan.FromSeconds(-1) }); Assert.True(result.Failed); Assert.Contains("DeliveredKpiWindow", result.FailureMessage); } [Fact] public void ZeroMaxParallelDeliveries_IsRejected() { var result = Validate(new NotificationOutboxOptions { MaxParallelDeliveries = 0 }); Assert.True(result.Failed); Assert.Contains("MaxParallelDeliveries", result.FailureMessage); } }