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));
}
}