Implement LmxOpcUa server — all 6 phases complete
Full OPC UA server on .NET Framework 4.8 (x86) exposing AVEVA System Platform Galaxy tags via MXAccess. Mirrors Galaxy object hierarchy as OPC UA address space, translating contained-name browse paths to tag-name runtime references. Components implemented: - Configuration: AppConfiguration with 4 sections, validator - Domain: ConnectionState, Quality, Vtq, MxDataTypeMapper, error codes - MxAccess: StaComThread, MxAccessClient (partial classes), MxProxyAdapter using strongly-typed ArchestrA.MxAccess COM interop - Galaxy Repository: SQL queries (hierarchy, attributes, change detection), ChangeDetectionService with auto-rebuild on deploy - OPC UA Server: LmxNodeManager (CustomNodeManager2), LmxOpcUaServer, OpcUaServerHost with programmatic config, SecurityPolicy None - Status Dashboard: HTTP server with HTML/JSON/health endpoints - Integration: Full 14-step startup, graceful shutdown, component wiring 175 tests (174 unit + 1 integration), all passing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
using ZB.MOM.WW.LmxOpcUa.Host.Configuration;
|
||||
|
||||
namespace ZB.MOM.WW.LmxOpcUa.Tests.Configuration
|
||||
{
|
||||
public class ConfigurationLoadingTests
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
[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);
|
||||
}
|
||||
|
||||
[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);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GalaxyRepository_Section_BindsCorrectly()
|
||||
{
|
||||
var config = LoadFromJson();
|
||||
config.GalaxyRepository.ConnectionString.ShouldContain("ZB");
|
||||
config.GalaxyRepository.ChangeDetectionIntervalSeconds.ShouldBe(30);
|
||||
config.GalaxyRepository.CommandTimeoutSeconds.ShouldBe(30);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Dashboard_Section_BindsCorrectly()
|
||||
{
|
||||
var config = LoadFromJson();
|
||||
config.Dashboard.Enabled.ShouldBe(true);
|
||||
config.Dashboard.Port.ShouldBe(8081);
|
||||
config.Dashboard.RefreshIntervalSeconds.ShouldBe(10);
|
||||
}
|
||||
|
||||
[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);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Validator_ValidConfig_ReturnsTrue()
|
||||
{
|
||||
var config = LoadFromJson();
|
||||
ConfigurationValidator.ValidateAndLog(config).ShouldBe(true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Validator_InvalidPort_ReturnsFalse()
|
||||
{
|
||||
var config = new AppConfiguration();
|
||||
config.OpcUa.Port = 0;
|
||||
ConfigurationValidator.ValidateAndLog(config).ShouldBe(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Validator_EmptyGalaxyName_ReturnsFalse()
|
||||
{
|
||||
var config = new AppConfiguration();
|
||||
config.OpcUa.GalaxyName = "";
|
||||
ConfigurationValidator.ValidateAndLog(config).ShouldBe(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user