using ZB.MOM.WW.ScadaBridge.Host; namespace ZB.MOM.WW.ScadaBridge.Host.Tests; /// /// Eager startup validation for the shared Host options (arch-review 08 round 2 /// NF4). Covers , /// , and /// in one file. The headline case: an /// empty normalises to a NULL SourceNode /// audit column, so it must fail the host at boot rather than silently degrade /// the audit trail. /// public class NodeOptionsValidatorTests { // ---- NodeOptions ---- [Fact] public void Node_DefaultsWithNodeName_AreValid() { var validator = new NodeOptionsValidator(); Assert.True(validator.Validate(null, new NodeOptions { NodeName = "node-a" }).Succeeded); } [Theory] [InlineData("")] [InlineData(" ")] public void Node_EmptyOrWhitespaceNodeName_Fails(string nodeName) { var validator = new NodeOptionsValidator(); var result = validator.Validate(null, new NodeOptions { NodeName = nodeName }); Assert.False(result.Succeeded); Assert.Contains(result.Failures!, f => f.Contains(nameof(NodeOptions.NodeName), StringComparison.Ordinal)); } [Fact] public void Node_ZeroRemotingPort_IsValid() { // CompositionRootTests uses RemotingPort = 0 to request a dynamic port. var validator = new NodeOptionsValidator(); Assert.True(validator.Validate(null, new NodeOptions { NodeName = "node-a", RemotingPort = 0 }).Succeeded); } [Theory] [InlineData(-1)] [InlineData(65_536)] public void Node_PortOutOfRange_Fails(int port) { var validator = new NodeOptionsValidator(); var result = validator.Validate(null, new NodeOptions { NodeName = "node-a", GrpcPort = port }); Assert.False(result.Succeeded); Assert.Contains(result.Failures!, f => f.Contains(nameof(NodeOptions.GrpcPort), StringComparison.Ordinal)); } // ---- DatabaseOptions ---- [Fact] public void Database_AllNull_IsValid() { // All three fields are nullable and role-dependent; null stays valid. var validator = new DatabaseOptionsValidator(); Assert.True(validator.Validate(null, new DatabaseOptions()).Succeeded); } [Fact] public void Database_WhitespaceValue_Fails() { var validator = new DatabaseOptionsValidator(); var result = validator.Validate(null, new DatabaseOptions { ConfigurationDb = " " }); Assert.False(result.Succeeded); Assert.Contains(result.Failures!, f => f.Contains(nameof(DatabaseOptions.ConfigurationDb), StringComparison.Ordinal)); } // ---- LoggingOptions ---- [Fact] public void Logging_DefaultInformation_IsValid() { var validator = new LoggingOptionsValidator(); Assert.True(validator.Validate(null, new LoggingOptions()).Succeeded); } [Theory] [InlineData("Verbose")] [InlineData("debug")] [InlineData("FATAL")] public void Logging_RecognisedLevel_IsValid(string level) { var validator = new LoggingOptionsValidator(); Assert.True(validator.Validate(null, new LoggingOptions { MinimumLevel = level }).Succeeded); } [Fact] public void Logging_UnknownLevel_Fails() { var validator = new LoggingOptionsValidator(); var result = validator.Validate(null, new LoggingOptions { MinimumLevel = "Chatty" }); Assert.False(result.Succeeded); Assert.Contains(result.Failures!, f => f.Contains(nameof(LoggingOptions.MinimumLevel), StringComparison.Ordinal)); } }