using ZB.MOM.WW.ScadaBridge.DelmiaNotifier; namespace ZB.MOM.WW.ScadaBridge.DelmiaNotifier.Tests; public class ConfigLoaderTests { /// Verifies that invalid endpoint lists are rejected when the configuration loads. /// The base URL list to load. [Theory] [InlineData("relative")] [InlineData("ftp://example.com")] [InlineData("https://good.example,broken")] [InlineData("http://")] public void Load_RejectsInvalidEndpointsBeforeDispatch(string urls) { var error = Assert.Throws(() => ConfigLoader.Load(System.Text.Json.JsonSerializer.Serialize(new { ScadaBridge = new { BaseUrls = urls } }))); Assert.Contains("ScadaBridge:BaseUrls", error.Message); Assert.Contains("HTTP", error.Message); } /// Verifies that splitting base URLs trims entries and drops empty ones. [Fact] public void SplitBaseUrls_trims_and_drops_empties() { var urls = ConfigLoader.SplitBaseUrls("a, b ,,c"); Assert.Equal(new[] { "a", "b", "c" }, urls); } /// Verifies that a null or whitespace base URL list yields no URLs. [Fact] public void SplitBaseUrls_null_or_whitespace_returns_empty() { Assert.Empty(ConfigLoader.SplitBaseUrls(null)); Assert.Empty(ConfigLoader.SplitBaseUrls(" ")); } /// Verifies that the timeout defaults to 30 seconds when it is omitted. [Fact] public void Load_defaults_timeout_to_30_when_omitted() { var cfg = ConfigLoader.Load("{\"ScadaBridge\":{\"BaseUrls\":\"http://x\"}}"); Assert.Equal(30, cfg.ScadaBridge.TimeoutSeconds); Assert.Equal("http://x", cfg.ScadaBridge.BaseUrls); } /// Verifies that loading reads every configured field. [Fact] public void Load_reads_all_fields() { var cfg = ConfigLoader.Load("{\"ScadaBridge\":{\"BaseUrls\":\"https://a,http://b\",\"TimeoutSeconds\":5,\"LogPath\":\"l.log\"}}"); Assert.Equal("https://a,http://b", cfg.ScadaBridge.BaseUrls); Assert.Equal(5, cfg.ScadaBridge.TimeoutSeconds); Assert.Equal("l.log", cfg.ScadaBridge.LogPath); } /// Verifies that an unset or whitespace environment key resolves to null. [Fact] public void ResolveApiKey_returns_null_when_unset_or_whitespace() { Assert.Null(ConfigLoader.ResolveApiKey(_ => null, new NotifierConfig())); Assert.Null(ConfigLoader.ResolveApiKey(_ => " ", new NotifierConfig())); } /// Verifies that a key present in the environment is returned. [Fact] public void ResolveApiKey_returns_value_when_present() { Assert.Equal("sbk_x", ConfigLoader.ResolveApiKey(n => n == "SCADABRIDGE_API_KEY" ? "sbk_x" : null, new NotifierConfig())); } /// Verifies that the API key is read from the ScadaBridge configuration section. [Fact] public void Load_reads_ApiKey_from_ScadaBridge_section() { var cfg = ConfigLoader.Load("{\"ScadaBridge\":{\"BaseUrls\":\"http://x\",\"ApiKey\":\"sbk_file\"}}"); Assert.Equal("sbk_file", cfg.ScadaBridge.ApiKey); } /// Verifies that the environment key takes precedence over the configured key. [Fact] public void ResolveApiKey_prefers_env_over_config() { var cfg = ConfigLoader.Load("{\"ScadaBridge\":{\"ApiKey\":\"sbk_file\"}}"); Assert.Equal("sbk_env", ConfigLoader.ResolveApiKey(n => n == "SCADABRIDGE_API_KEY" ? "sbk_env" : null, cfg)); } /// Verifies that the configured key is used when the environment key is unset or blank. [Fact] public void ResolveApiKey_falls_back_to_config_when_env_unset_or_blank() { var cfg = ConfigLoader.Load("{\"ScadaBridge\":{\"ApiKey\":\" sbk_file \"}}"); Assert.Equal("sbk_file", ConfigLoader.ResolveApiKey(_ => null, cfg)); Assert.Equal("sbk_file", ConfigLoader.ResolveApiKey(_ => " ", cfg)); } /// Verifies that the environment key is trimmed the same way as the configured key. [Fact] public void ResolveApiKey_trims_env_value_like_the_file_value() { Assert.Equal("sbk_env", ConfigLoader.ResolveApiKey(_ => " sbk_env \t", new NotifierConfig())); } /// Verifies that key resolution reports whether the environment or the file supplied the key. [Fact] public void ResolveApiKey_reports_which_source_supplied_the_key() { var cfg = ConfigLoader.Load("{\"ScadaBridge\":{\"ApiKey\":\"sbk_file\"}}"); ConfigLoader.ResolveApiKey(_ => "sbk_env", cfg, out var fromEnv); ConfigLoader.ResolveApiKey(_ => null, cfg, out var fromFile); ConfigLoader.ResolveApiKey(_ => null, new NotifierConfig(), out var none); Assert.Equal(ConfigLoader.ApiKeySourceEnvironment, fromEnv); Assert.Equal(ConfigLoader.ApiKeySourceFile, fromFile); Assert.Null(none); } /// Verifies that the API key stays null when the configuration omits it. [Fact] public void Load_leaves_ApiKey_null_when_absent() { var cfg = ConfigLoader.Load("{\"ScadaBridge\":{\"BaseUrls\":\"http://x\"}}"); Assert.Null(cfg.ScadaBridge.ApiKey); } /// Verifies that key resolution returns null when neither source supplies a key. [Fact] public void ResolveApiKey_returns_null_when_neither_source_set() { var cfg = ConfigLoader.Load("{\"ScadaBridge\":{\"ApiKey\":\" \"}}"); Assert.Null(ConfigLoader.ResolveApiKey(_ => null, cfg)); } }