Files
lmxopcua/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/SdkServiceLevelPublisherTests.cs
Joseph Doherty bd6c0b4d3d docs: complete XML doc comments via fixdocs (2757 to 131 findings)
Add missing <returns>/<param>/<summary>/<typeparam> tags and clean up
misused inheritdoc across 481 files so the documented API surface is
complete. Documentation-only (zero code lines changed). The 131 remaining
findings are inheritdoc-style warnings deliberately left to preserve
hand-written implementation rationale (plan-decision notes, race-condition
explanations).
2026-06-03 12:34:34 -04:00

100 lines
3.7 KiB
C#

using Microsoft.Extensions.Logging.Abstractions;
using Opc.Ua.Server;
using Shouldly;
using Xunit;
namespace ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests;
/// <summary>
/// #81 residual — verifies <see cref="SdkServiceLevelPublisher"/> locates the standard
/// <c>VariableIds.Server_ServiceLevel</c> node through the SDK's DiagnosticsNodeManager and
/// writes the byte value. Boots a real <see cref="StandardServer"/> on a free port so the
/// SDK populates its predefined diagnostics nodes — that's what production sees.
/// </summary>
public sealed class SdkServiceLevelPublisherTests : IDisposable
{
private static CancellationToken Ct => TestContext.Current.CancellationToken;
private readonly string _pkiRoot = Path.Combine(
Path.GetTempPath(),
$"otopcua-pki-{Guid.NewGuid():N}");
/// <summary>Verifies that the publisher writes values to the standard Server.ServiceLevel variable.</summary>
/// <returns>A task that represents the asynchronous test operation.</returns>
[Fact]
public async Task Publish_writes_value_to_Server_ServiceLevel_variable()
{
var server = new StandardServer();
await using var host = new OpcUaApplicationHost(
new OpcUaApplicationHostOptions
{
ApplicationName = "OtOpcUa.SvcLevel",
ApplicationUri = $"urn:OtOpcUa.SvcLevel:{Guid.NewGuid():N}",
OpcUaPort = AllocateFreePort(),
PublicHostname = "localhost",
PkiStoreRoot = _pkiRoot,
},
NullLogger<OpcUaApplicationHost>.Instance);
await host.StartAsync(server, Ct);
var publisher = new SdkServiceLevelPublisher(
server.CurrentInstance,
NullLogger<SdkServiceLevelPublisher>.Instance);
publisher.Publish(200);
var variable = server.CurrentInstance.ServerObject.ServiceLevel;
variable.ShouldNotBeNull("Server.ServiceLevel must be present in the address space");
variable.Value.ShouldBe((byte)200);
}
/// <summary>Verifies that publishing service level values is idempotent when called multiple times.</summary>
/// <returns>A task that represents the asynchronous test operation.</returns>
[Fact]
public async Task Publish_is_idempotent_when_called_multiple_times()
{
var server = new StandardServer();
await using var host = new OpcUaApplicationHost(
new OpcUaApplicationHostOptions
{
ApplicationName = "OtOpcUa.SvcLevel.Idem",
ApplicationUri = $"urn:OtOpcUa.SvcLevel.Idem:{Guid.NewGuid():N}",
OpcUaPort = AllocateFreePort(),
PublicHostname = "localhost",
PkiStoreRoot = _pkiRoot,
},
NullLogger<OpcUaApplicationHost>.Instance);
await host.StartAsync(server, Ct);
var publisher = new SdkServiceLevelPublisher(
server.CurrentInstance,
NullLogger<SdkServiceLevelPublisher>.Instance);
publisher.Publish(100);
publisher.Publish(150);
publisher.Publish(240);
server.CurrentInstance.ServerObject.ServiceLevel.Value.ShouldBe((byte)240);
}
private static int AllocateFreePort()
{
using var listener = new System.Net.Sockets.TcpListener(System.Net.IPAddress.Loopback, 0);
listener.Start();
var port = ((System.Net.IPEndPoint)listener.LocalEndpoint).Port;
listener.Stop();
return port;
}
/// <summary>Disposes and cleans up the test resources.</summary>
public void Dispose()
{
if (Directory.Exists(_pkiRoot))
{
try { Directory.Delete(_pkiRoot, recursive: true); }
catch { /* best-effort */ }
}
}
}