using Microsoft.Extensions.Configuration;
using Shouldly;
using Xunit;
using ZB.MOM.WW.LmxOpcUa.Host.Configuration;
namespace ZB.MOM.WW.LmxOpcUa.Tests.Configuration
{
///
/// Verifies that application configuration binds correctly from appsettings and that validation catches invalid bridge settings.
///
public class ConfigurationLoadingTests
{
///
/// Loads the application configuration from the repository appsettings file for binding tests.
///
/// The bound application configuration snapshot.
private static AppConfiguration LoadFromJson()
{
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: false)
.Build();
var config = new AppConfiguration();
configuration.GetSection("OpcUa").Bind(config.OpcUa);
configuration.GetSection("MxAccess").Bind(config.MxAccess);
configuration.GetSection("GalaxyRepository").Bind(config.GalaxyRepository);
configuration.GetSection("Dashboard").Bind(config.Dashboard);
return config;
}
///
/// Confirms that the OPC UA section binds the endpoint and session settings expected by the bridge.
///
[Fact]
public void OpcUa_Section_BindsCorrectly()
{
var config = LoadFromJson();
config.OpcUa.Port.ShouldBe(4840);
config.OpcUa.EndpointPath.ShouldBe("/LmxOpcUa");
config.OpcUa.ServerName.ShouldBe("LmxOpcUa");
config.OpcUa.GalaxyName.ShouldBe("ZB");
config.OpcUa.MaxSessions.ShouldBe(100);
config.OpcUa.SessionTimeoutMinutes.ShouldBe(30);
}
///
/// Confirms that the MXAccess section binds runtime timeout and reconnect settings correctly.
///
[Fact]
public void MxAccess_Section_BindsCorrectly()
{
var config = LoadFromJson();
config.MxAccess.ClientName.ShouldBe("LmxOpcUa");
config.MxAccess.ReadTimeoutSeconds.ShouldBe(5);
config.MxAccess.WriteTimeoutSeconds.ShouldBe(5);
config.MxAccess.MaxConcurrentOperations.ShouldBe(10);
config.MxAccess.MonitorIntervalSeconds.ShouldBe(5);
config.MxAccess.AutoReconnect.ShouldBe(true);
config.MxAccess.ProbeStaleThresholdSeconds.ShouldBe(60);
}
///
/// Confirms that the Galaxy repository section binds connection and polling settings correctly.
///
[Fact]
public void GalaxyRepository_Section_BindsCorrectly()
{
var config = LoadFromJson();
config.GalaxyRepository.ConnectionString.ShouldContain("ZB");
config.GalaxyRepository.ChangeDetectionIntervalSeconds.ShouldBe(30);
config.GalaxyRepository.CommandTimeoutSeconds.ShouldBe(30);
config.GalaxyRepository.ExtendedAttributes.ShouldBe(false);
}
///
/// Confirms that extended-attribute loading defaults to disabled when not configured.
///
[Fact]
public void GalaxyRepository_ExtendedAttributes_DefaultsFalse()
{
var config = new GalaxyRepositoryConfiguration();
config.ExtendedAttributes.ShouldBe(false);
}
///
/// Confirms that the extended-attribute flag can be enabled through configuration binding.
///
[Fact]
public void GalaxyRepository_ExtendedAttributes_BindsFromJson()
{
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: false)
.AddInMemoryCollection(new[] { new System.Collections.Generic.KeyValuePair("GalaxyRepository:ExtendedAttributes", "true") })
.Build();
var config = new GalaxyRepositoryConfiguration();
configuration.GetSection("GalaxyRepository").Bind(config);
config.ExtendedAttributes.ShouldBe(true);
}
///
/// Confirms that the dashboard section binds operator-dashboard settings correctly.
///
[Fact]
public void Dashboard_Section_BindsCorrectly()
{
var config = LoadFromJson();
config.Dashboard.Enabled.ShouldBe(true);
config.Dashboard.Port.ShouldBe(8081);
config.Dashboard.RefreshIntervalSeconds.ShouldBe(10);
}
///
/// Confirms that the default configuration objects start with the expected bridge defaults.
///
[Fact]
public void DefaultValues_AreCorrect()
{
var config = new AppConfiguration();
config.OpcUa.Port.ShouldBe(4840);
config.MxAccess.ClientName.ShouldBe("LmxOpcUa");
config.GalaxyRepository.ChangeDetectionIntervalSeconds.ShouldBe(30);
config.Dashboard.Enabled.ShouldBe(true);
}
///
/// Confirms that a valid configuration passes startup validation.
///
[Fact]
public void Validator_ValidConfig_ReturnsTrue()
{
var config = LoadFromJson();
ConfigurationValidator.ValidateAndLog(config).ShouldBe(true);
}
///
/// Confirms that an invalid OPC UA port is rejected by startup validation.
///
[Fact]
public void Validator_InvalidPort_ReturnsFalse()
{
var config = new AppConfiguration();
config.OpcUa.Port = 0;
ConfigurationValidator.ValidateAndLog(config).ShouldBe(false);
}
///
/// Confirms that an empty Galaxy name is rejected because the bridge requires a namespace target.
///
[Fact]
public void Validator_EmptyGalaxyName_ReturnsFalse()
{
var config = new AppConfiguration();
config.OpcUa.GalaxyName = "";
ConfigurationValidator.ValidateAndLog(config).ShouldBe(false);
}
}
}