diff --git a/src/ZB.MOM.WW.ScadaBridge.Transport/TransportOptionsValidator.cs b/src/ZB.MOM.WW.ScadaBridge.Transport/TransportOptionsValidator.cs index d5dd9eb5..43799b13 100644 --- a/src/ZB.MOM.WW.ScadaBridge.Transport/TransportOptionsValidator.cs +++ b/src/ZB.MOM.WW.ScadaBridge.Transport/TransportOptionsValidator.cs @@ -48,6 +48,10 @@ public sealed class TransportOptionsValidator : OptionsValidatorBase 0, + $"ScadaBridge:Transport:MaxConcurrentImportSessions must be positive " + + $"(was {options.MaxConcurrentImportSessions}); a zero/negative cap rejects every import session forever."); + builder.RequireThat(options.MaxUnlockAttemptsPerIpPerHour > 0, $"ScadaBridge:Transport:MaxUnlockAttemptsPerIpPerHour must be positive " + $"(was {options.MaxUnlockAttemptsPerIpPerHour}); it caps unlock attempts per IP address per hour."); diff --git a/tests/ZB.MOM.WW.ScadaBridge.Transport.Tests/TransportOptionsValidatorTests.cs b/tests/ZB.MOM.WW.ScadaBridge.Transport.Tests/TransportOptionsValidatorTests.cs index 1c40c78c..47a3a213 100644 --- a/tests/ZB.MOM.WW.ScadaBridge.Transport.Tests/TransportOptionsValidatorTests.cs +++ b/tests/ZB.MOM.WW.ScadaBridge.Transport.Tests/TransportOptionsValidatorTests.cs @@ -38,6 +38,22 @@ public class TransportOptionsValidatorTests Assert.Contains("MaxBundleSizeMb", result.FailureMessage); } + [Fact] + public void ZeroMaxConcurrentImportSessions_IsRejected() + { + var result = Validate(new TransportOptions { MaxConcurrentImportSessions = 0 }); + Assert.True(result.Failed); + Assert.Contains("MaxConcurrentImportSessions", result.FailureMessage); // FAILS today: validates clean + } + + [Fact] + public void NegativeMaxConcurrentImportSessions_IsRejected() + { + var result = Validate(new TransportOptions { MaxConcurrentImportSessions = -1 }); + Assert.True(result.Failed); + Assert.Contains("MaxConcurrentImportSessions", result.FailureMessage); + } + [Fact] public void ZeroPbkdf2Iterations_IsRejected() {