SdkServiceLevelPublisher writes Server.ServiceLevel through the SDK's ServerObjectState — the standard OPC UA non-transparent-redundancy signal clients use to pick a primary. Writes are guarded by DiagnosticsLock so concurrent SDK diagnostics scans don't fight with our updates. DeferredServiceLevelPublisher mirrors the DeferredAddressSpaceSink late- binding pattern: Akka actors resolve IServiceLevelPublisher at construction, hosted service swaps the SDK publisher in after StandardServer.Start. Host Program.cs registers DeferredServiceLevelPublisher as the singleton bound to IServiceLevelPublisher; OtOpcUaServerHostedService gets it injected and fills it once IServerInternal is available. Tests boot a real StandardServer on a free port (cross-platform), call Publish, then verify ServerObject.ServiceLevel.Value reflects the write. 5 new tests; OpcUaServer suite now 45/45 green (was 40, +5). Closes #81 residual. Unblocks Task 60 (OPC UA dual-endpoint + ServiceLevel tests).
49 lines
1.3 KiB
C#
49 lines
1.3 KiB
C#
using Shouldly;
|
|
using Xunit;
|
|
using ZB.MOM.WW.OtOpcUa.Commons.OpcUa;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests;
|
|
|
|
public sealed class DeferredServiceLevelPublisherTests
|
|
{
|
|
[Fact]
|
|
public void Publish_before_SetInner_is_a_safe_noop()
|
|
{
|
|
var deferred = new DeferredServiceLevelPublisher();
|
|
|
|
Should.NotThrow(() => deferred.Publish(123));
|
|
}
|
|
|
|
[Fact]
|
|
public void Publish_after_SetInner_routes_to_the_inner()
|
|
{
|
|
var recording = new RecordingPublisher();
|
|
var deferred = new DeferredServiceLevelPublisher();
|
|
deferred.SetInner(recording);
|
|
|
|
deferred.Publish(200);
|
|
|
|
recording.LastValue.ShouldBe((byte)200);
|
|
}
|
|
|
|
[Fact]
|
|
public void SetInner_null_reverts_to_Null_publisher()
|
|
{
|
|
var recording = new RecordingPublisher();
|
|
var deferred = new DeferredServiceLevelPublisher();
|
|
deferred.SetInner(recording);
|
|
deferred.Publish(50);
|
|
|
|
deferred.SetInner(null);
|
|
deferred.Publish(99);
|
|
|
|
recording.LastValue.ShouldBe((byte)50, "writes after SetInner(null) must not reach the previous inner");
|
|
}
|
|
|
|
private sealed class RecordingPublisher : IServiceLevelPublisher
|
|
{
|
|
public byte? LastValue { get; private set; }
|
|
public void Publish(byte serviceLevel) => LastValue = serviceLevel;
|
|
}
|
|
}
|