From 7c787b8b6452a0d1245a671ee86dd05bb7cdf709 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Fri, 9 Oct 2026 14:22:41 -0400 Subject: [PATCH] test(host): an invalid SqlServer:Schema is consumer-gated, not a Resolve-time throw Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe --- .../ServerHistorianOptionsValidatorTests.cs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests/ServerHistorianOptionsValidatorTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests/ServerHistorianOptionsValidatorTests.cs index d6447d73..00945b11 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests/ServerHistorianOptionsValidatorTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests/ServerHistorianOptionsValidatorTests.cs @@ -339,4 +339,40 @@ public sealed class ServerHistorianOptionsValidatorTests [Fact] public void SqlServer_backend_not_consumed_passes_without_connection_string() => SqlSut(null).Validate(null, new ServerHistorianOptions { Backend = "SqlServer" }).Failed.ShouldBeFalse(); + + private static IConfiguration BadSchemaConfig(bool alarmHistorianEnabled) => + new ConfigurationBuilder().AddInMemoryCollection(new Dictionary + { + ["AlarmHistorian:Enabled"] = alarmHistorianEnabled ? "true" : "false", + ["ServerHistorian:SqlServer:ConnectionString"] = "Server=localhost;Database=h", + ["ServerHistorian:SqlServer:Schema"] = "bad;schema", + }).Build(); + + /// + /// An invalid ServerHistorian:SqlServer:Schema must not fail the host when nothing consumes the section: + /// (which Program.cs calls unconditionally) does not throw and + /// the validator does not check it — the same consumer gate the connection string has. + /// + [Fact] + public void SqlServer_invalid_schema_not_consumed_neither_resolve_nor_validation_fails() + { + var configuration = BadSchemaConfig(alarmHistorianEnabled: false); + var options = new ServerHistorianOptions { Backend = "SqlServer" }; + + Should.NotThrow(() => HistorianBackendRegistry.Resolve(options, configuration)); + new ServerHistorianOptionsValidator(configuration).Validate(null, options).Failed.ShouldBeFalse(); + } + + /// Consumed (here by AlarmHistorian alone), the same invalid schema is a named validator error. + [Fact] + public void SqlServer_invalid_schema_consumed_is_a_validator_error_naming_the_key() + { + var configuration = BadSchemaConfig(alarmHistorianEnabled: true); + var options = new ServerHistorianOptions { Backend = "SqlServer" }; + + Should.NotThrow(() => HistorianBackendRegistry.Resolve(options, configuration)); + var result = new ServerHistorianOptionsValidator(configuration).Validate(null, options); + result.Failed.ShouldBeTrue(); + result.Failures.ShouldContain(f => f.Contains("ServerHistorian:SqlServer:Schema")); + } }