fix(opcuaserver): chunked, per-item-isolated WriteValues with typed partial-failure outcome

This commit is contained in:
Joseph Doherty
2026-08-15 12:32:44 -04:00
parent 8ef02506f7
commit 6bf1fb3754
7 changed files with 468 additions and 82 deletions
@@ -9,7 +9,8 @@ namespace ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests;
/// <summary>
/// OpcUaServer-004 — a fresh <see cref="OtOpcUaNodeManager"/> whose <c>CreateAddressSpace</c> has NOT
/// yet run (i.e. the server has not started) has a null <c>_root</c>. Every public address-space mutator
/// (<see cref="OtOpcUaNodeManager.WriteValue"/>, <see cref="OtOpcUaNodeManager.WriteAlarmCondition"/>,
/// (<see cref="OtOpcUaNodeManager.WriteValue"/>, <see cref="OtOpcUaNodeManager.WriteValues"/>,
/// <see cref="OtOpcUaNodeManager.WriteAlarmCondition"/>,
/// <see cref="OtOpcUaNodeManager.EnsureFolder"/>, <see cref="OtOpcUaNodeManager.EnsureVariable"/>,
/// <see cref="OtOpcUaNodeManager.MaterialiseAlarmCondition"/>) must now fail with a legible
/// <see cref="InvalidOperationException"/> instead of a bare NRE out of <c>ResolveParentFolder</c> /
@@ -78,6 +79,28 @@ public sealed class NodeManagerPreStartGuardTests : IDisposable
}
}
/// <summary>The batched mutator guards the same way — and it does so BEFORE its empty-batch early-return,
/// so a pre-start caller gets the legible failure regardless of what the batch happens to carry (an empty
/// batch returning quietly would make the guard depend on payload rather than on server state).</summary>
[Fact]
public async Task WriteValues_before_CreateAddressSpace_throws_InvalidOperationException()
{
var (host, nm) = await BuildPreStartNodeManagerAsync();
try
{
Should.Throw<InvalidOperationException>(() => nm.WriteValues(new[]
{
new ValueWrite("eq-1/temp", 1.0, OpcUaStatus.Good, DateTime.UtcNow, AddressSpaceRealm.Uns),
}));
Should.Throw<InvalidOperationException>(() => nm.WriteValues([]));
}
finally
{
await host.DisposeAsync();
}
}
[Fact]
public async Task MaterialiseAlarmCondition_before_CreateAddressSpace_throws_InvalidOperationException()
{