fix(code-review): resolve Batch 3 wave A (OpcUaServer history/guard, ControlPlane topology gate)
- OpcUaServer-002: HistoryRead-Events NumValuesPerNode==0 now maps to unbounded (int.MaxValue) instead of the backend default-cap sentinel; no Core.Abstractions contract change (+EventMaxEvents helper tests) - OpcUaServer-004: EnsureAddressSpaceCreated guard on public mutators -> clear InvalidOperationException instead of bare NRE if called pre-start (+tests) - OpcUaServer-003: Deferred (endUtc inclusive/exclusive needs live Wonderware boundary confirmation) - Configuration-013: wire DraftValidator.ValidateClusterTopology into AdminOperationsActor deploy gate (read-only, no migration) (+2 tests)
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// OpcUaServer-002 — unit coverage for <see cref="OtOpcUaNodeManager.EventMaxEvents"/>, the pure
|
||||
/// helper that maps a HistoryRead-Events <c>NumValuesPerNode</c> request cap onto the
|
||||
/// <c>IHistorianDataSource.ReadEventsAsync</c> <c>maxEvents</c> argument. Per OPC UA Part 4/11,
|
||||
/// <c>NumValuesPerNode == 0</c> means "no limit — return ALL values", so the helper translates 0 to
|
||||
/// UNBOUNDED (<see cref="int.MaxValue"/>) rather than the backend's <c>maxEvents <= 0</c>
|
||||
/// "use the default cap" sentinel; a positive value passes through clamped to <see cref="int.MaxValue"/>.
|
||||
/// </summary>
|
||||
public sealed class NodeManagerEventMaxEventsTests
|
||||
{
|
||||
/// <summary>0 ("no limit" per the spec) ⇒ int.MaxValue (unbounded), NOT the 0/default-cap sentinel.</summary>
|
||||
[Fact]
|
||||
public void Zero_maps_to_int_max()
|
||||
{
|
||||
OtOpcUaNodeManager.EventMaxEvents(0u).ShouldBe(int.MaxValue);
|
||||
}
|
||||
|
||||
/// <summary>A normal positive cap passes through unchanged.</summary>
|
||||
[Fact]
|
||||
public void Normal_value_passes_through()
|
||||
{
|
||||
OtOpcUaNodeManager.EventMaxEvents(50u).ShouldBe(50);
|
||||
OtOpcUaNodeManager.EventMaxEvents(1u).ShouldBe(1);
|
||||
}
|
||||
|
||||
/// <summary>A value above int.MaxValue clamps to int.MaxValue (mirrors ClampToInt's saturation).</summary>
|
||||
[Fact]
|
||||
public void Value_above_int_max_clamps()
|
||||
{
|
||||
OtOpcUaNodeManager.EventMaxEvents((uint)int.MaxValue + 1u).ShouldBe(int.MaxValue);
|
||||
OtOpcUaNodeManager.EventMaxEvents(uint.MaxValue).ShouldBe(int.MaxValue);
|
||||
}
|
||||
|
||||
/// <summary>int.MaxValue exactly passes through (boundary — not clamped down).</summary>
|
||||
[Fact]
|
||||
public void Int_max_exactly_passes_through()
|
||||
{
|
||||
OtOpcUaNodeManager.EventMaxEvents((uint)int.MaxValue).ShouldBe(int.MaxValue);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user