using Microsoft.Extensions.Options;
namespace ZB.MOM.WW.ScadaBridge.NotificationOutbox.Tests;
///
/// Tests for the options validator: 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);
/// Verifies that the default options are valid.
[Fact]
public void DefaultOptions_AreValid()
{
var result = Validate(new NotificationOutboxOptions());
Assert.True(result.Succeeded, result.FailureMessage);
}
/// Verifies that a zero dispatch interval is rejected.
[Fact]
public void ZeroDispatchInterval_IsRejected()
{
var result = Validate(new NotificationOutboxOptions { DispatchInterval = TimeSpan.Zero });
Assert.True(result.Failed);
Assert.Contains("DispatchInterval", result.FailureMessage);
}
/// Verifies that a zero dispatch batch size is rejected.
[Fact]
public void ZeroDispatchBatchSize_IsRejected()
{
var result = Validate(new NotificationOutboxOptions { DispatchBatchSize = 0 });
Assert.True(result.Failed);
Assert.Contains("DispatchBatchSize", result.FailureMessage);
}
/// Verifies that a zero stuck-age threshold is rejected.
[Fact]
public void ZeroStuckAgeThreshold_IsRejected()
{
var result = Validate(new NotificationOutboxOptions { StuckAgeThreshold = TimeSpan.Zero });
Assert.True(result.Failed);
Assert.Contains("StuckAgeThreshold", result.FailureMessage);
}
/// Verifies that a zero terminal-row retention is rejected.
[Fact]
public void ZeroTerminalRetention_IsRejected()
{
var result = Validate(new NotificationOutboxOptions { TerminalRetention = TimeSpan.Zero });
Assert.True(result.Failed);
Assert.Contains("TerminalRetention", result.FailureMessage);
}
/// Verifies that a zero purge interval is rejected.
[Fact]
public void ZeroPurgeInterval_IsRejected()
{
var result = Validate(new NotificationOutboxOptions { PurgeInterval = TimeSpan.Zero });
Assert.True(result.Failed);
Assert.Contains("PurgeInterval", result.FailureMessage);
}
/// Verifies that a zero delivered-KPI window is rejected.
[Fact]
public void ZeroDeliveredKpiWindow_IsRejected()
{
var result = Validate(new NotificationOutboxOptions { DeliveredKpiWindow = TimeSpan.Zero });
Assert.True(result.Failed);
Assert.Contains("DeliveredKpiWindow", result.FailureMessage);
}
/// Verifies that a negative delivered-KPI window is rejected.
[Fact]
public void NegativeDeliveredKpiWindow_IsRejected()
{
var result = Validate(new NotificationOutboxOptions { DeliveredKpiWindow = TimeSpan.FromSeconds(-1) });
Assert.True(result.Failed);
Assert.Contains("DeliveredKpiWindow", result.FailureMessage);
}
/// Verifies that a zero maximum parallel deliveries value is rejected.
[Fact]
public void ZeroMaxParallelDeliveries_IsRejected()
{
var result = Validate(new NotificationOutboxOptions { MaxParallelDeliveries = 0 });
Assert.True(result.Failed);
Assert.Contains("MaxParallelDeliveries", result.FailureMessage);
}
}